From 7fc54465ed532c216acc151865162287949065ac Mon Sep 17 00:00:00 2001 From: Tim Cuthbertson Date: Thu, 28 Aug 2025 21:17:13 +1000 Subject: [PATCH 1/2] use $KOKA_PATH as a low-priority include path --- src/Compile/Options.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Compile/Options.hs b/src/Compile/Options.hs index 62e21107b..43954a807 100644 --- a/src/Compile/Options.hs +++ b/src/Compile/Options.hs @@ -862,7 +862,10 @@ processInitialOptions flags0 opts (localDir,localLibDir,localShareDir,localBinDir) <- getKokaDirs (localLibDir flags) (localShareDir flags) buildDir - normalizedIncludes <- mapM realPath ("." : (localShareDir ++ "/lib") : includePath flags) + pathsFromEnv <- fmap undelimPaths (getEnvVar "KOKA_PATH") + let allIncludes = nub $ filter (not . null) ("." : (localShareDir ++ "/lib") : includePath flags ++ pathsFromEnv) + normalizedIncludes <- mapM realPath allIncludes + -- _ <- trace ("Normalized includes: " ++ show normalizedIncludes) $ return () -- cc ccmd <- if (ccompPath flags == "") then detectCC (target flags) From 7b33acdd283102adf35cbbcbb40ba47bed0734e3 Mon Sep 17 00:00:00 2001 From: Tim Cuthbertson Date: Fri, 29 Aug 2025 07:25:20 +1000 Subject: [PATCH 2/2] add support for resolving C libraries via pkg-config --- src/Common/File.hs | 4 +- src/Compile/CodeGen.hs | 70 ++++++++++++++++++++++------ src/Platform/cpp/Platform/FileIO.hs | 22 +++++---- src/Platform/wasm/Platform/FileIO.hs | 4 ++ 4 files changed, 75 insertions(+), 25 deletions(-) diff --git a/src/Common/File.hs b/src/Common/File.hs index fc8997e5d..7747f9086 100644 --- a/src/Common/File.hs +++ b/src/Common/File.hs @@ -15,7 +15,7 @@ module Common.File( , searchPaths, searchPathsSuffixes, searchPathsEx, searchPathsCanonical , getMaximalPrefixPath , searchProgram - , runSystem, runSystemRaw, runCmd, runCmdRead, runCmdEnv + , runSystem, runSystemRaw, runCmd, runCmdRead, runCmdReadExit, runCmdEnv , getProgramPath -- * Strings @@ -63,7 +63,7 @@ import Platform.FileIO ( doesFileExist, doesDirectoryExist, createDirectoryIfMi , removeFileIfExists , getCwd, realPath , getEnvVar, getEnvPaths, getProgramPath - , runSystem, runSystemRaw, runCmd, runCmdRead, runCmdEnv + , runSystem, runSystemRaw, runCmd, runCmdRead, runCmdReadExit, runCmdEnv , getFileSize ) import Platform.Filetime import qualified Platform.Runtime as B (copyBinaryFileWithMetaData) diff --git a/src/Compile/CodeGen.hs b/src/Compile/CodeGen.hs index b9aa6b499..c78d4ca97 100644 --- a/src/Compile/CodeGen.hs +++ b/src/Compile/CodeGen.hs @@ -34,6 +34,7 @@ import Type.Pretty( Env(colorizing,coreIface,coreShowDef,context,importsMap) ) import Syntax.Syntax import Syntax.Colorize( colorize ) import Syntax.GenDoc( genDoc ) +import System.Exit( ExitCode(..) ) import qualified Core.Core as Core import qualified Core.Pretty @@ -454,7 +455,9 @@ copyCLibrary term flags sequential cc outDir eimport = case Core.eimportLookup (buildType flags) "library" eimport of Nothing -> return [] Just clib - -> do mb <- do mbSearch <- search [] [ searchCLibrary flags cc clib (ccompLibDirs flags) + -> do mb <- do mbSearch <- search [] [ searchCLibrary term flags cc clib (ccompLibDirs flags) + , pkgConfigCLibrary term flags cc clib $ + fromMaybe ("lib" ++ clib) (lookup "pkg-config" eimport) , case lookup "vcpkg" eimport of Just pkg -> vcpkgCLibrary term flags sequential cc eimport clib pkg @@ -479,7 +482,7 @@ copyCLibrary term flags sequential cc outDir eimport -> -- TODO: suggest conan and/or vcpkg install? do termWarning term flags $ text "unable to find C library:" <+> color (colorSource (colorScheme flags)) (text clib) <-> - text " hint: provide \"--cclibdir\" as an option, or use \"syslib\" in an extern import?" + text " hint: provide \"--cclibdir\" as an option, ensure \"pkg-config\" can find the library, or use \"syslib\" in an extern import?" raiseIO ("unable to find C library " ++ clib ++ "\nlibrary search paths: " ++ show (ccompLibDirs flags)) where @@ -491,14 +494,22 @@ copyCLibrary term flags sequential cc outDir eimport Right res -> return (Right res) Left warns' -> search (warns ++ warns') ios -searchCLibrary :: Flags -> CC -> FilePath -> [FilePath] -> IO (Either [Doc] (FilePath {-libPath-},[FilePath] {-include paths-})) -searchCLibrary flags cc clib searchPaths - = do mbPath <- -- looking for specific suffixes is not ideal but it differs among plaforms (e.g. pcre2-8 is only pcre2-8d on Windows) - -- and the actual name of the library is not easy to extract from vcpkg (we could read - -- the lib/config/.pc information and parse the Libs field but that seems fragile as well) - do let suffixes = (if (buildType flags <= Debug) then ["d","_d","-d","-debug","_debug","-dbg","_dbg"] else []) - -- trace ("search in: " ++ show searchPaths) $ - searchPathsSuffixes searchPaths [] suffixes (ccLibFile cc clib) +searchCLibPath :: Terminal -> Flags -> CC -> FilePath -> [FilePath] -> IO (Maybe FilePath) +searchCLibPath term flags cc clib searchPaths + = -- looking for specific suffixes is not ideal but it differs among plaforms (e.g. pcre2-8 is only pcre2-8d on Windows) + -- and the actual name of the library is not easy to extract from vcpkg (we could read + -- the lib/config/.pc information and parse the Libs field but that seems fragile as well) + do let suffixes = (if (buildType flags <= Debug) then ["d","_d","-d","-debug","_debug","-dbg","_dbg"] else []) + let libFilename = ccLibFile cc clib + -- trace ("search in: " ++ show searchPaths) $ + result <- searchPathsSuffixes searchPaths [] suffixes libFilename + phaseVerboseIO term flags 3 "libPath" $ + \penv -> text (fromMaybe (libFilename ++ " not found in " ++ show searchPaths) result) + return result + +searchCLibrary :: Terminal -> Flags -> CC -> FilePath -> [FilePath] -> IO (Either [Doc] (FilePath {-libPath-},[FilePath] {-include paths-})) +searchCLibrary term flags cc clib searchPaths + = do mbPath <- searchCLibPath term flags cc clib searchPaths case mbPath of Just fname -> case reverse (splitPath fname) of @@ -510,9 +521,34 @@ searchCLibrary flags cc clib searchPaths {--------------------------------------------------------------- - Package managers: Conan and VCPkg + Dependency management: pkg-config, Conan and VCPkg ---------------------------------------------------------------} +-- This currently only inspects the given package, +-- it could be improved to handle transitive dependencies. +pkgConfigCLibrary :: Terminal -> Flags -> CC -> FilePath -> FilePath -> IO (Either [Doc] (FilePath {-libPath-},[FilePath] {-include paths-})) +pkgConfigCLibrary term flags cc clib pkgname + = do pkgConfigExe <- searchProgram "pkg-config" + case pkgConfigExe of + Nothing -> return $ Left [] + Just pkgConfigExe + -> do libDir <- getPath "libdir" + libPath <- searchCLibPath term flags cc clib (maybeToList libDir) + includePath <- maybe (return Nothing) (\_ -> getPath "includedir") libPath + return $ case (libPath, includePath) of + (Just libPath, Just includePath) -> Right (libPath, [includePath]) + _ -> Left [text $ "No pkg-config definition found for " ++ clib] + where + getPath variable + = do (status, outFull, err) <- runCommandReadAllExit term flags [] [pkgConfigExe, "--variable=" ++ variable, pkgname] + let out = trim outFull + case status of + ExitFailure _ -> do phaseVerboseIO term flags 3 "shell" $ \penv -> text ("failed: " ++ (trim err)) + return Nothing + ExitSuccess -> do phaseVerboseIO term flags 3 "out" $ \penv -> text out + return (Just out) + + conanCLibrary :: Terminal -> Flags -> (IO () -> IO ()) -> CC -> [(String,String)] -> FilePath -> String -> IO (Either [Doc] (FilePath,[FilePath])) conanCLibrary term flags sequential cc eimport clib pkg = do mbConanCmd <- searchProgram (conan flags) @@ -537,7 +573,7 @@ conanCLibrary term flags sequential cc eimport clib pkg -> do termPhase term $ color (colorInterpreter (colorScheme flags)) $ text "package : conan" <+> clrSource (text pkgName) -- <.> colon <+> clrSource (text pkgDir) let libDir = pkgDir ++ "/lib" - searchCLibrary flags cc clib [libDir] + searchCLibrary term flags cc clib [libDir] where pkgBase @@ -617,7 +653,7 @@ vcpkgCLibrary term flags sequential cc eimport clib pkg ++ (if buildType flags <= Debug then "/debug/lib" else "/lib") termPhase term $ color (colorInterpreter (colorScheme flags)) $ text "package : vcpkg" <+> clrSource (text pkg) - mbInstalled <- searchCLibrary flags cc clib [libDir] + mbInstalled <- searchCLibrary term flags cc clib [libDir] case mbInstalled of Right _ -> return mbInstalled Left _ -> install root libDir vcpkg @@ -644,7 +680,7 @@ vcpkgCLibrary term flags sequential cc eimport clib pkg return (Left []) else do termPhase term (color (colorInterpreter (colorScheme flags)) (text "install: vcpkg package:") <+> clrSource (text pkg)) sequential $ runCommand term flags installCmd - searchCLibrary flags cc clib [libDir] -- try to find again after install + searchCLibrary term flags cc clib [libDir] -- try to find again after install clibsFromCore flags core = externalImportKeyFromCore (target flags) (buildType flags) core "library" csyslibsFromCore flags core = externalImportKeyFromCore (target flags) (buildType flags) core "syslib" @@ -732,6 +768,12 @@ runCommandReadAll term flags env cargs@(cmd:args) runCmdRead env cmd (filter (not . null) args) `catchIO` (\msg -> raiseIO ("error : " ++ msg ++ "\ncommand: " ++ command)) +runCommandReadAllExit :: Terminal -> Flags -> [(String,String)] -> [String] -> IO (ExitCode,String,String) +runCommandReadAllExit term flags env cargs@(cmd:args) + = do let command = unwords (shellQuote cmd : map shellQuote args) + phaseVerboseIO term flags 3 "command" $ \penv -> text command -- cmd ++ " [" ++ concat (intersperse "," args) ++ "]") + runCmdReadExit env cmd (filter (not . null) args) + runCommandEnv :: Terminal -> Flags -> [(String,String)] -> [String] -> IO () runCommandEnv term flags env cargs@(cmd:args) = do let command = unwords (shellQuote cmd : map shellQuote args) diff --git a/src/Platform/cpp/Platform/FileIO.hs b/src/Platform/cpp/Platform/FileIO.hs index 42965531e..58a9b460f 100644 --- a/src/Platform/cpp/Platform/FileIO.hs +++ b/src/Platform/cpp/Platform/FileIO.hs @@ -37,7 +37,7 @@ module Platform.FileIO( , getHomeDirectory , getTemporaryDirectory -- * Process execution - , runSystem, runSystemRaw, runCmd, runCmdRead, runCmdEnv + , runSystem, runSystemRaw, runCmd, runCmdRead, runCmdReadExit, runCmdEnv ) where import System.IO @@ -198,17 +198,21 @@ runCmd cmd args runCmdRead :: [(String,String)] -> String -> [String] -> IO (String,String) runCmdRead extraEnv cmd args + = do (exitCode,out,err) <- runCmdReadExit extraEnv cmd args + case exitCode of + ExitFailure i -> raiseIO ("command failed (exit code " ++ show i ++ ")") -- \n " ++ concat (intersperse " " (cmd:args))) + ExitSuccess -> return (out,err) + +runCmdReadExit :: [(String,String)] -> String -> [String] -> IO (ExitCode,String,String) +runCmdReadExit extraEnv cmd args = do mbEnv <- buildEnv extraEnv (_, Just hout, Just herr, process) <- createProcess (proc cmd args){ env = mbEnv, std_out = CreatePipe, std_err = CreatePipe } exitCode <- waitForProcess process - case exitCode of - ExitFailure i -> do -- hClose hout - raiseIO ("command failed (exit code " ++ show i ++ ")") -- \n " ++ concat (intersperse " " (cmd:args))) - ExitSuccess -> do out <- hGetContents hout - err <- hGetContents herr - -- hClose hout - return (out,err) - + out <- hGetContents hout + err <- hGetContents herr + -- hClose hout + -- hClose herr + return (exitCode,out,err) runCmdEnv :: [(String,String)] -> String -> [String] -> IO () runCmdEnv extraEnv cmd args diff --git a/src/Platform/wasm/Platform/FileIO.hs b/src/Platform/wasm/Platform/FileIO.hs index 6ddafe60b..b9a28df21 100644 --- a/src/Platform/wasm/Platform/FileIO.hs +++ b/src/Platform/wasm/Platform/FileIO.hs @@ -42,6 +42,7 @@ import System.IO import System.Directory( doesFileExist, doesDirectoryExist, createDirectoryIfMissing , getCurrentDirectory, canonicalizePath, removeFile , getFileSize ) +import System.Exit( ExitCode(..) ) import Data.Char( toLower ) import Common.Failure( raiseIO, catchIO ) @@ -128,5 +129,8 @@ runCmd _ _ = raiseIO "command execution not available in WASM/WASI" runCmdRead :: [(String,String)] -> String -> [String] -> IO (String,String) runCmdRead _ _ _ = raiseIO "command execution not available in WASM/WASI" +runCmdReadExit :: [(String,String)] -> String -> [String] -> IO (ExitCode,String,String) +runCmdRead _ _ _ = raiseIO "command execution not available in WASM/WASI" + runCmdEnv :: [(String,String)] -> String -> [String] -> IO () runCmdEnv _ _ _ = raiseIO "command execution not available in WASM/WASI"