diff --git a/src/_premake_init.lua b/src/_premake_init.lua index 4a6f080e55..6c2cbb8307 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -923,6 +923,14 @@ end, } + api.register { + name = "toolsetpaths", + scope = "config", + kind = "keyed:keyed:path", -- { toolset_name = { tool_name = path } } + tokens = true, + pathVars = true, + } + api.register { name = "undefines", scope = "config", diff --git a/src/base/api.lua b/src/base/api.lua index ff04a382f9..bf0808ad44 100755 --- a/src/base/api.lua +++ b/src/base/api.lua @@ -1205,3 +1205,40 @@ function newoption(opt) p.option.add(opt) end + + +--- +-- Set the path for a specific tool within a toolset. +-- +-- @param toolsetName +-- The name of the toolset (e.g., "gcc", "clang"). +-- @param toolName +-- The name of the tool (e.g., "cc", "cxx", "ld"). +-- @param toolPath +-- The path to the tool executable. +--- +function toolsetpath(toolsetName, toolName, toolPath) + local cfg = api.scope.current + if not cfg then + error("toolsetpath must be called within a configuration block", 2) + end + + -- Get the toolsetpaths field definition + local field = p.field.get("toolsetpaths") + if not field then + error("toolsetpaths field not registered", 2) + end + + -- Construct the data table + local data = { + [toolsetName] = { + [toolName] = toolPath + } + } + + -- Store the data using configset.store + local status, err = configset.store(cfg, field, data) + if err then + error(err, 2) + end +end diff --git a/src/tools/clang.lua b/src/tools/clang.lua index d92cdd0e63..ed013954a9 100644 --- a/src/tools/clang.lua +++ b/src/tools/clang.lua @@ -350,6 +350,11 @@ } function clang.gettoolname(cfg, tool) + -- Check toolsetpaths first + if cfg.toolsetpaths and cfg.toolsetpaths[cfg.toolset] and cfg.toolsetpaths[cfg.toolset][tool] then + return cfg.toolsetpaths[cfg.toolset][tool] + end + local toolset, version = p.tools.canonical(cfg.toolset or p.CLANG) local value = clang.tools[tool] if type(value) == "function" then diff --git a/src/tools/cosmocc.lua b/src/tools/cosmocc.lua index 4758604a47..0430cf64ae 100644 --- a/src/tools/cosmocc.lua +++ b/src/tools/cosmocc.lua @@ -23,5 +23,10 @@ cosmocc.tools = { } function cosmocc.gettoolname(cfg, tool) + -- Check toolsetpaths first + if cfg.toolsetpaths and cfg.toolsetpaths[cfg.toolset] and cfg.toolsetpaths[cfg.toolset][tool] then + return cfg.toolsetpaths[cfg.toolset][tool] + end + return cosmocc.tools[tool] end diff --git a/src/tools/dotnet.lua b/src/tools/dotnet.lua index 95151799da..103001aa5e 100644 --- a/src/tools/dotnet.lua +++ b/src/tools/dotnet.lua @@ -255,6 +255,11 @@ -- function dotnet.gettoolname(cfg, tool) + -- Check toolsetpaths first + if cfg.toolsetpaths and cfg.toolsetpaths[cfg.toolset] and cfg.toolsetpaths[cfg.toolset][tool] then + return cfg.toolsetpaths[cfg.toolset][tool] + end + local compilers = { msnet = "csc", mono = "mcs", diff --git a/src/tools/emcc.lua b/src/tools/emcc.lua index cf5e31f616..f7300b24cf 100644 --- a/src/tools/emcc.lua +++ b/src/tools/emcc.lua @@ -22,7 +22,13 @@ emcc.tools = { -- flags correctly to emcc builds. emcc.shared.profile = nil emcc.ldflags.profile = nil +emcc.getsharedlibarg = function(cfg) return "" end function emcc.gettoolname(cfg, tool) + -- Check toolsetpaths first + if cfg.toolsetpaths and cfg.toolsetpaths[cfg.toolset] and cfg.toolsetpaths[cfg.toolset][tool] then + return cfg.toolsetpaths[cfg.toolset][tool] + end + return emcc.tools[tool] end diff --git a/src/tools/gcc.lua b/src/tools/gcc.lua index 81d6b4035c..a845dafc88 100644 --- a/src/tools/gcc.lua +++ b/src/tools/gcc.lua @@ -706,6 +706,11 @@ } function gcc.gettoolname(cfg, tool) + -- Check toolsetpaths first + if cfg.toolsetpaths and cfg.toolsetpaths[cfg.toolset] and cfg.toolsetpaths[cfg.toolset][tool] then + return cfg.toolsetpaths[cfg.toolset][tool] + end + local toolset, version = p.tools.canonical(cfg.toolset or p.GCC) if toolset == p.tools.gcc and version ~= nil then version = "-" .. version diff --git a/src/tools/msc.lua b/src/tools/msc.lua index 6b621ea477..c40d45db4e 100644 --- a/src/tools/msc.lua +++ b/src/tools/msc.lua @@ -479,6 +479,11 @@ -- function msc.gettoolname(cfg, tool) + -- Check toolsetpaths first + if cfg.toolsetpaths and cfg.toolsetpaths[cfg.toolset] and cfg.toolsetpaths[cfg.toolset][tool] then + return cfg.toolsetpaths[cfg.toolset][tool] + end + return nil end diff --git a/src/tools/snc.lua b/src/tools/snc.lua index b6b396c531..f0c1572ab9 100644 --- a/src/tools/snc.lua +++ b/src/tools/snc.lua @@ -139,6 +139,11 @@ } function snc.gettoolname(cfg, tool) + -- Check toolsetpaths first + if cfg.toolsetpaths and cfg.toolsetpaths[cfg.toolset] and cfg.toolsetpaths[cfg.toolset][tool] then + return cfg.toolsetpaths[cfg.toolset][tool] + end + local names = snc.tools[cfg.architecture] or snc.tools[cfg.system] or {} return names[tool] end diff --git a/tests/tools/test_clang.lua b/tests/tools/test_clang.lua index 38fbf6b9c7..830cad001c 100644 --- a/tests/tools/test_clang.lua +++ b/tests/tools/test_clang.lua @@ -48,6 +48,16 @@ test.isequal("windres-16", clang.gettoolname(cfg, "rc")) end +-- +-- Verify that toolsetpath overrides the default tool name. +-- +function suite.toolsetpathOverridesDefault() + toolset "clang" + toolsetpath("clang", "cc", "/path/to/my/custom/clang") + prepare() + test.isequal("/path/to/my/custom/clang", clang.gettoolname(cfg, "cc")) +end + -- -- Check Mac OS X deployment target flags -- diff --git a/tests/tools/test_dotnet.lua b/tests/tools/test_dotnet.lua index ff58fd2ee1..eebb77e7a0 100644 --- a/tests/tools/test_dotnet.lua +++ b/tests/tools/test_dotnet.lua @@ -45,6 +45,16 @@ test.isequal("csc", dotnet.gettoolname(cfg, "csc")) end +-- +-- Verify that toolsetpath overrides the default tool name. +-- +function suite.toolsetpathOverridesDefault() + toolset "dotnet" + toolsetpath("dotnet", "csc", "/path/to/my/custom/csc") + prepare() + test.isequal("/path/to/my/custom/csc", dotnet.gettoolname(cfg, "csc")) +end + -- -- Check support for the `csversion` API diff --git a/tests/tools/test_emcc.lua b/tests/tools/test_emcc.lua index b994cb7db1..ec220395cc 100644 --- a/tests/tools/test_emcc.lua +++ b/tests/tools/test_emcc.lua @@ -46,3 +46,13 @@ function suite.tools_onWASM64() test.isequal("wasm64", cfg.architecture) end +-- +-- Verify that toolsetpath overrides the default tool name. +-- +function suite.toolsetpathOverridesDefault() + toolset "emcc" + toolsetpath("emcc", "cc", "/path/to/my/custom/emcc") + prepare() + test.isequal("/path/to/my/custom/emcc", emcc.gettoolname(cfg, "cc")) +end + diff --git a/tests/tools/test_gcc.lua b/tests/tools/test_gcc.lua index 5eb7a44d36..d7cafc492a 100644 --- a/tests/tools/test_gcc.lua +++ b/tests/tools/test_gcc.lua @@ -66,6 +66,16 @@ test.isequal("windres-16", gcc.gettoolname(cfg, "rc")) end +-- +-- Verify that toolsetpath overrides the default tool name. +-- +function suite.toolsetpathOverridesDefault() + toolset "gcc" + toolsetpath("gcc", "cc", "/path/to/my/custom/gcc") + prepare() + test.isequal("/path/to/my/custom/gcc", gcc.gettoolname(cfg, "cc")) +end + -- -- By default, the -MMD -MP are used to generate dependencies. -- diff --git a/tests/tools/test_msc.lua b/tests/tools/test_msc.lua index e070b829ef..7880192171 100644 --- a/tests/tools/test_msc.lua +++ b/tests/tools/test_msc.lua @@ -26,6 +26,16 @@ end +-- +-- Verify that toolsetpath overrides the default tool name. +-- +function suite.toolsetpathOverridesDefault() + toolset "msc" + toolsetpath("msc", "cc", "C:/path/to/my/custom/cl.exe") + prepare() + test.isequal("C:/path/to/my/custom/cl.exe", msc.gettoolname(cfg, "cc")) +end + -- -- Check the optimization flags. -- diff --git a/tests/tools/test_snc.lua b/tests/tools/test_snc.lua index ed5416a8a6..27a21d261b 100644 --- a/tests/tools/test_snc.lua +++ b/tests/tools/test_snc.lua @@ -45,6 +45,16 @@ test.isnil(snc.gettoolname(cfg, "ar")) end +-- +-- Verify that toolsetpath overrides the default tool name. +-- +function suite.toolsetpathOverridesDefault() + toolset "snc" + toolsetpath("snc", "cc", "/path/to/my/custom/snc_cc") + prepare() + test.isequal("/path/to/my/custom/snc_cc", snc.gettoolname(cfg, "cc")) +end + -- -- By default, the -MMD -MP are used to generate dependencies. diff --git a/website/docs/toolsetpath.md b/website/docs/toolsetpath.md new file mode 100644 index 0000000000..2a464c9b92 --- /dev/null +++ b/website/docs/toolsetpath.md @@ -0,0 +1,41 @@ +Specifies the path to a specific tool executable for a given toolset. This allows overriding the default tool lookup behavior of Premake. + +```lua +toolsetpath(toolsetName, toolName, toolPath) +``` + +### Parameters + +`toolsetName` +: The name of the toolset (e.g., `"gcc"`, `"clang"`, `"msc"`). + +`toolName` +: The name of the tool within the toolset (e.g., `"cc"` for C compiler, `"cxx"` for C++ compiler, `"ld"` for linker, `"ar"` for archiver). + +`toolPath` +: The absolute or relative path to the tool executable. + +### Applies To + +Project configurations. + +### Example + +```lua +project "MyProject" + kind "ConsoleApp" + language "C++" + system "Linux" + + configuration "Release" + toolset "gcc" + -- Specify a custom path for the GCC C++ compiler + toolsetpath("gcc", "cxx", "/opt/my_custom_gcc/bin/g++") + + configuration "Debug" + toolset "clang" + -- Specify a custom path for the Clang C compiler + toolsetpath("clang", "cc", "/usr/local/clang-15/bin/clang") +``` + +In this example, the `toolsetpath` function is used to specify custom paths for the C++ compiler in the "Release" configuration (using GCC) and the C compiler in the "Debug" configuration (using Clang). \ No newline at end of file diff --git a/website/docs/toolsetpaths.md b/website/docs/toolsetpaths.md new file mode 100644 index 0000000000..9acd3d4d6e --- /dev/null +++ b/website/docs/toolsetpaths.md @@ -0,0 +1,53 @@ +Specifies custom paths for tool executables for one or more toolsets using a nested table structure. This field is primarily intended for internal use by Premake modules and actions. **End users should generally prefer using [`toolsetpath`](toolsetpath.md)** for specifying custom tool paths, as it provides a more user-friendly syntax. + +```lua +toolsetpaths { + ["toolsetName"] = { + ["toolName"] = "toolPath", + -- ... more tools for this toolset + }, + -- ... more toolsets +} +``` + +### Parameters + +The `toolsetpaths` field accepts a table where keys are `toolsetName` (the name of the toolset, e.g., `"gcc"`, `"clang"`, `"msc"`) and values are nested tables. + +The nested tables have `toolName` (the name of the tool within the toolset, e.g., `"cc"` for C compiler, `"cxx"` for C++ compiler, `"ld"` for linker, `"ar"`) as keys and `toolPath` (the absolute or relative path to the tool executable) as values. + +### Applies To + +Project configurations. + +### Example + +```lua +project "MyProject" + kind "ConsoleApp" + language "C++" + system "Linux" + + configuration "Release" + toolset "gcc" + -- Example of using the toolsetpaths field (less common for end users) + toolsetpaths { + gcc = { + cc = "/opt/my_custom_gcc/bin/gcc", + cxx = "/opt/my_custom_gcc/bin/g++", + ar = "/opt/my_custom_gcc/bin/ar" + } + } + + configuration "Debug" + toolset "clang" + -- Prefer using the toolsetpath function for clarity + toolsetpath("clang", "cc", "/usr/local/clang-15/bin/clang") + toolsetpath("clang", "ld", "/usr/local/clang-15/bin/ld") +``` + +In this example, both the `toolsetpaths` field and the `toolsetpath` function are shown. The `toolsetpath` function is the recommended approach for end users. + +### See Also ### + +* [toolsetpath](toolsetpath.md) diff --git a/website/sidebars.js b/website/sidebars.js index bb98603642..ac4a0cffe8 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -271,6 +271,7 @@ module.exports = { 'thumbmode', 'toolchainversion', 'toolset', + 'toolsetpath', 'toolsversion', 'undefines', 'usage',