diff --git a/src/comp/Error.hs b/src/comp/Error.hs index 048a11cfc..5d820ee9a 100644 --- a/src/comp/Error.hs +++ b/src/comp/Error.hs @@ -1118,6 +1118,7 @@ data ErrMsg = | EMissingUserFile String [String] | EUnrecognizedCmdLineText String | EUnknownVerilogSim String [String] Bool + | EMissingVPIWrapperFile String Bool -- ABin (.ba) file issues | WExtraABinFiles [String] @@ -4416,6 +4417,12 @@ getErrorText (WNonDemotableErrors tags) = in s2par ("Cannot demote the following error" ++ s ++ ":") $$ nest 2 (sepList (map text tags) comma)) +getErrorText (EMissingVPIWrapperFile fname is_dpi) = + (System 95, empty, + let ifctype = if is_dpi then "DPI" else "VPI" + in s2par ("Cannot find the " ++ ifctype ++ " file " ++ ishow fname ++ + " in the Verilog search path.")) + -- Runtime errors getErrorText (EMutuallyExclusiveRulesFire r1 r2) = (Runtime 1, empty, diff --git a/src/comp/VPIWrappers.hs b/src/comp/VPIWrappers.hs index 73c0230c0..a76d6bc1b 100644 --- a/src/comp/VPIWrappers.hs +++ b/src/comp/VPIWrappers.hs @@ -300,8 +300,8 @@ mkVPIRegisterBody name has_return stores_handles = genVPIRegistrationArray :: ErrorHandle -> Flags -> String -> [String] -> [ForeignFunction] -> - IO () -genVPIRegistrationArray _ _ _ _ [] = return () + IO [String] +genVPIRegistrationArray _ _ _ _ [] = return [] genVPIRegistrationArray errh flags prefix blurb ffs = do let -- generate the registration array file name c_filename = mkVPIArrayCName (vdir flags) prefix @@ -316,6 +316,8 @@ genVPIRegistrationArray errh flags prefix blurb ffs = writeFileCatch errh c_filename c_contents -- report the file to the user with relative path unless (quiet flags) $ putStrLnF $ "VPI registration array file created: " ++ c_filename_rel + -- return the file name + return [c_filename] mkVPIRegistrationArray :: Flags -> String -> [ForeignFunction] -> Bool -> CCFragment mkVPIRegistrationArray flags prefix ffs with_fn = diff --git a/src/comp/bsc.hs b/src/comp/bsc.hs index 07877e769..a442240e3 100644 --- a/src/comp/bsc.hs +++ b/src/comp/bsc.hs @@ -7,6 +7,7 @@ import System.Environment(getArgs, getProgName) import System.Process(runInteractiveProcess, waitForProcess) import System.Process(system) import System.Exit(ExitCode(ExitFailure, ExitSuccess)) +import System.FilePath(takeDirectory) import System.IO(hFlush, stdout, hPutStr, stderr, hGetContents, hClose, hSetBuffering, BufferMode(LineBuffering)) import System.IO(hSetEncoding, latin1) import System.Posix.Files(fileMode, unionFileModes, ownerExecuteMode, groupExecuteMode, setFileMode, getFileStatus, fileAccess) @@ -16,7 +17,7 @@ import Data.Char(isSpace, toLower, ord) import Data.List(intersect, nub, partition, intersperse, sort, isPrefixOf, isSuffixOf, unzip5, intercalate) import Data.Time.Clock.POSIX(getPOSIXTime) -import Data.Maybe(isJust, isNothing {-, fromMaybe-}) +import Data.Maybe(isJust, isNothing) import Numeric(showOct) import Control.Monad(when, unless, filterM, liftM, foldM) @@ -25,6 +26,7 @@ import Control.Concurrent(forkIO) import Control.Concurrent.MVar(newEmptyMVar, putMVar, takeMVar) import qualified Control.Exception as CE import qualified Data.Map as M +import qualified Data.Set as S import ListMap(lookupWithDefault) import SCC(scc) @@ -34,7 +36,7 @@ import ParseOp import PFPrint import Util(headOrErr, fromJustOrErr, joinByFst, quote) import FileNameUtil(baseName, hasDotSuf, dropSuf, dirName, mangleFileName, - mkAName, mkVName, mkVPICName, mkVPIArrayCName, + mkAName, mkVName, mkVPICName, mkNameWithoutSuffix, mkSoName, mkObjName, mkMakeName, bscSrcSuffix, bseSrcSuffix, binSuffix, @@ -42,7 +44,8 @@ import FileNameUtil(baseName, hasDotSuf, dropSuf, dirName, mangleFileName, objSuffix, useSuffix, genFileName, createEncodedFullFilePath, getFullFilePath, getRelativeFilePath) -import FileIOUtil(writeFileCatch, readFileMaybe, removeFileCatch) +import FileIOUtil(writeFileCatch, readFileMaybe, removeFileCatch, + readFilePath) import TopUtils import SystemCheck(doSystemCheck) import BuildSystem @@ -1531,12 +1534,13 @@ cmdCompileBluesimCFile flags cName = do return (cmd, oName, msg) -- returns the name of the object file created -compileVPICFile :: ErrorHandle -> Flags -> String -> IO String -compileVPICFile errh flags cName = do +compileVPICFile :: ErrorHandle -> Flags -> [String] -> String -> IO String +compileVPICFile errh flags incdirs cName = do let oName = mkObjName Nothing "" (dropSuf cName) -- show is used for quoting let incflags = map (("-I"++) . show) (cIncPath flags) ++ - ["-I" ++ show (bluespecDir flags) ++ "/VPI"] + ["-I" ++ show (bluespecDir flags) ++ "/VPI"] ++ + map (\d -> "-I" ++ d) incdirs switches = incflags ++ [ "-fPIC" , "-c" @@ -2083,13 +2087,14 @@ vGenFFuncs :: ErrorHandle -> Flags -> TimeInfo -> String -> IO (TimeInfo, [String]) vGenFFuncs errh flags t prefix cfilenames_unique [] = return (t,[]) vGenFFuncs errh flags t prefix cfilenames_unique ffuncs = do - t <- - if (useDPI flags) then return t + (t, vpiarray_filenames) <- + if (useDPI flags) then return (t, []) else do -- generate the vpi_startup_array file blurb <- mkGenFileHeader flags - genVPIRegistrationArray errh flags prefix blurb ffuncs - timestampStr flags "generate VPI registration array" t + filenames <- genVPIRegistrationArray errh flags prefix blurb ffuncs + t <- timestampStr flags "generate VPI registration array" t + return (t, filenames) -- compile user-supplied C files let (cfiles1, ofiles1) = partition (\f -> hasDotSuf cSuffix f || @@ -2101,23 +2106,30 @@ vGenFFuncs errh flags t prefix cfilenames_unique ffuncs = do ofiles2 <- mapM (compileUserCFile errh flags True) cfiles1 t <- timestampStr flags "compile user-provided C files" t -{- - -- XXX If any of BSC's pre-compiled .ba libraries has a VPI wrapper - -- XXX that goes along with it, they would need to included here? - do let to = fromMaybe "." (vdir flags) - mapM_ (\src -> do let dst = to ++ "/" ++ (baseName src) - copyFileCatch errh src dst) - vpi_wrapper_c_h_files --} - (t, ofiles3) <- if (useDPI flags) then return (t, []) else do -- compile all necessary vpi wrapper files - let mkVPIFileName s = mkVPICName (vdir flags) prefix s - vpifiles = map (mkVPIFileName . getIdString . ff_name) ffuncs ++ - [ mkVPIArrayCName (vdir flags) prefix ] - files <- mapM (compileVPICFile errh flags) vpifiles + + -- first, find the VPI wrapper files in the vsearch path + let findVPIWrapperFile ffunc = do + let ffunc_name = getIdString (ff_name ffunc) + vpiwrapper_filename = mkVPICName Nothing "" ffunc_name + mfile <- readFilePath errh noPosition False vpiwrapper_filename (vPath flags) + case mfile of + Nothing -> bsError errh [(noPosition, EMissingVPIWrapperFile vpiwrapper_filename False)] + Just (_, filename) -> return filename + vpiwrapper_filenames <- mapM findVPIWrapperFile ffuncs + + -- collect the directories of the VPI wrapper files + -- to use as a search path for header files when compiling + -- the VPI registration array file + let vpidirs = S.toList (S.fromList (map takeDirectory vpiwrapper_filenames)) + + -- include the vpi registration array file + wrapper_files <- mapM (compileVPICFile errh flags []) vpiwrapper_filenames + array_files <- mapM (compileVPICFile errh flags vpidirs) vpiarray_filenames + let files = wrapper_files ++ array_files t <- timestampStr flags "compile VPI wrapper files" t return (t, files) diff --git a/testsuite/bsc.options/Makefile b/testsuite/bsc.options/Makefile index 6d5cfc7cb..11d93938b 100644 --- a/testsuite/bsc.options/Makefile +++ b/testsuite/bsc.options/Makefile @@ -3,7 +3,7 @@ CONFDIR = $(realpath ..) DONTKEEPFILES = *.post-m4 *.post-m4-stage1 \ - simfiles bfiles vfiles incfiles srcfiles \ + simfiles bfiles vfiles incfiles srcfiles vfiles_link \ SplitIfNested.bs.expandif.atsexpand.expected \ NoSplitIfNested.bs.expandif.atsexpand.expected \ NoSplitIfNested.bs.noexpandif.atsexpand.expected \ diff --git a/testsuite/bsc.options/options.exp b/testsuite/bsc.options/options.exp index 7c779286f..f6494b274 100644 --- a/testsuite/bsc.options/options.exp +++ b/testsuite/bsc.options/options.exp @@ -127,8 +127,12 @@ files_exist { simfiles/mkDummyModule.cxx \ ########### # -# Test that vpi_wrapper_* files are written to vdir -# or (if no vdir) to the same directory where the source file sits +# Test that the compile stage writes 'vpi_wrapper_*' files to vdir +# or (if no vdir) to the same directory where the source file sits. +# +# And test that the linking step can find VPI wrapper files +# by looking through the Verilog search path, to successfully +# compile the wrappers and to compile the registration array. # # The directory of the source file is not the current directory # (where BSC was invoked from) when -u is used to compile files @@ -136,23 +140,56 @@ files_exist { simfiles/mkDummyModule.cxx \ # the source file given on the command line include a directory # (which is what we will test here). +# --- +# Test compile without vdir + +nukedir srcfiles +erase_many {vpi_*.{c,h,o}} + +# Set up the source file in a directory +mkdir srcfiles +copy GCD.bsv srcfiles + +compile_verilog_pass srcfiles/GCD.bsv {} {-p srcfiles:+} +files_exist {srcfiles/vpi_wrapper_my_time.h srcfiles/vpi_wrapper_my_time.c} + +# --- +# Test compile with vdir + +nukedir srcfiles +nukedir vfiles +erase_many {vpi_*.{c,h,o}} + # Set up the source file in a directory mkdir srcfiles copy GCD.bsv srcfiles -# Remove vpi_wrapper files, so we can test they are generated -erase_many {vfiles/vpi_wrapper*} +# Create the vdir +mkdir vfiles -# Test with vdir compile_verilog_pass srcfiles/GCD.bsv {} {-vdir vfiles -p srcfiles:+} files_exist {vfiles/vpi_wrapper_my_time.h vfiles/vpi_wrapper_my_time.c} -# Remove vpi_wrapper files, so we can test they are generated -erase_many {vpi_wrapper*} +# The above will have placed vpi wrappers in 'vfiles/' +# so now we test that linking can find it, +# both with or without its own other vdir -# Test without vdir -compile_verilog_pass srcfiles/GCD.bsv {} {-p srcfiles:+} -files_exist {srcfiles/vpi_wrapper_my_time.h srcfiles/vpi_wrapper_my_time.c} +# --- +# Test link with vdir + +nukedir vfiles_link +mkdir vfiles_link + +link_verilog_pass {srcfiles/my_time.ba} {sysGCD} {-vsearch vfiles:+ -vdir vfiles_link} +files_exist {vfiles/vpi_wrapper_my_time.o vfiles_link/vpi_startup_array.o} + +# --- +# Test link without vdir + +erase_many {vfiles/vpi_*.o vpi_*.{c,h,o}} + +link_verilog_pass {srcfiles/my_time.ba} {sysGCD} {-vsearch vfiles:+} +files_exist {vfiles/vpi_wrapper_my_time.o vpi_startup_array.o} ########### #