diff options
| author | ruki <[email protected]> | 2025-01-25 16:22:23 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-01-25 16:22:23 +0800 |
| commit | e1914d8136d2cd5efb44e7c24a822b14cf599c8c (patch) | |
| tree | 1eeb74ffa5f86adbeb446fbef1aafcad96d2e7ce /tests | |
| parent | 669d2db9d3468aa0dc2edea9771ace9bb99f0d19 (diff) | |
| parent | beff9a0f84ce1ebdd1eeb85caee55500320595a3 (diff) | |
Merge pull request #6114 from xmake-io/toolchain
Add custom unknown toolchain support
Diffstat (limited to 'tests')
17 files changed, 612 insertions, 31 deletions
diff --git a/tests/apis/custom_toolchain/src/foo.cpp b/tests/apis/custom_toolchain/src/foo.cpp new file mode 100644 index 000000000..1a1fb3425 --- /dev/null +++ b/tests/apis/custom_toolchain/src/foo.cpp @@ -0,0 +1,5 @@ +#include "foo.h" + +int add(int a, int b) { + return a + b; +} diff --git a/tests/apis/custom_toolchain/src/foo.h b/tests/apis/custom_toolchain/src/foo.h new file mode 100644 index 000000000..d2506bca9 --- /dev/null +++ b/tests/apis/custom_toolchain/src/foo.h @@ -0,0 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + +int add(int a, int b); + +#ifdef __cplusplus +} +#endif diff --git a/tests/apis/custom_toolchain/src/test.cpp b/tests/apis/custom_toolchain/src/test.cpp new file mode 100644 index 000000000..7cdb7d93f --- /dev/null +++ b/tests/apis/custom_toolchain/src/test.cpp @@ -0,0 +1,5 @@ +#include "foo.h" + +int main(int argc, char** argv) { + return add(1, 2); +} diff --git a/tests/apis/custom_toolchain/xmake.lua b/tests/apis/custom_toolchain/xmake.lua new file mode 100644 index 000000000..03d2b5344 --- /dev/null +++ b/tests/apis/custom_toolchain/xmake.lua @@ -0,0 +1,17 @@ +add_rules("mode.debug", "mode.release") + +add_moduledirs("xmake/modules") +add_toolchaindirs("xmake/toolchains") + +set_toolchains("my-c6000") + +target("test") + set_kind("static") + add_files("src/foo.cpp") + +target("demo") + set_kind("binary") + add_deps("test") + add_files("src/test.cpp") + + diff --git a/tests/apis/custom_toolchain/xmake/modules/core/tools/ar6x.lua b/tests/apis/custom_toolchain/xmake/modules/core/tools/ar6x.lua new file mode 100644 index 000000000..821b955e3 --- /dev/null +++ b/tests/apis/custom_toolchain/xmake/modules/core/tools/ar6x.lua @@ -0,0 +1,27 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, TBOOX Open Source Group. +-- +-- @author ruki +-- @file ar6x.lua +-- + +inherit("core.tools.ar") + +-- init it +function init(self) + self:set("arflags", "-r") +end + diff --git a/tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x.lua b/tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x.lua new file mode 100644 index 000000000..f350808da --- /dev/null +++ b/tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x.lua @@ -0,0 +1,207 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, TBOOX Open Source Group. +-- +-- @author ruki +-- @file cl6x.lua +-- + +-- imports +import("core.base.option") +import("core.base.global") +import("core.project.policy") +import("core.language.language") +import("utils.progress") + +-- init it +function init(self) +end + +-- make the symbol flag +function nf_symbol(self, level) + -- only for source kind + local kind = self:kind() + if language.sourcekinds()[kind] then + local maps = _g.symbol_maps + if not maps then + maps = + { + debug = "-g" + } + _g.symbol_maps = maps + end + return maps[level .. '_' .. kind] or maps[level] + end +end + +-- make the optimize flag +function nf_optimize(self, level) + local maps = + { + none = "-O0" + , fast = "-O1" + , faster = "-O2" + , fastest = "-O3" + , smallest = "-m3" + , aggressive = "-O3" + } + return maps[level] +end + +-- make the define flag +function nf_define(self, macro) + return "-D" .. macro +end + +-- make the undefine flag +function nf_undefine(self, macro) + return "-U" .. macro +end + +-- make the includedir flag +function nf_includedir(self, dir) + return {"-I" .. dir} +end + +-- make the sysincludedir flag +function nf_sysincludedir(self, dir) + return nf_includedir(self, dir) +end + +-- make the link flag +function nf_link(self, lib) + if not lib:endswith(".a") and not lib:endswith(".so") then + lib = "lib" .. lib .. ".a" + end + return "-l" .. lib +end + +-- make the syslink flag +function nf_syslink(self, lib) + return nf_link(self, lib) +end + +-- make the linkdir flag +function nf_linkdir(self, dir) + return {"-i" .. path.translate(dir)} +end + +-- make the rpathdir flag +function nf_rpathdir(self, dir, opt) + opt = opt or {} + local extra = opt.extra + if extra and extra.installonly then + return + end + dir = path.translate(dir) + return {"-rpath=" .. dir} +end + +-- make the link arguments list +function linkargv(self, objectfiles, targetkind, targetfile, flags, opt) + local argv = table.join("-z", "--output_file=" .. targetfile, objectfiles, flags) + return self:program(), argv +end + +-- link the target file +-- +-- maybe we need to use os.vrunv() to show link output when enable verbose information +-- @see https://github.com/xmake-io/xmake/discussions/2916 +-- +function link(self, objectfiles, targetkind, targetfile, flags, opt) + opt = opt or {} + os.mkdir(path.directory(targetfile)) + local program, argv = linkargv(self, objectfiles, targetkind, targetfile, flags) + if option.get("verbose") then + os.execv(program, argv, {envs = self:runenvs(), shell = opt.shell}) + else + os.vrunv(program, argv, {envs = self:runenvs(), shell = opt.shell}) + end +end + +-- make the compile arguments list +function compargv(self, sourcefile, objectfile, flags) + return self:program(), table.join("-c", "--preproc_with_compile", flags, "--output_file=" .. objectfile, sourcefile) +end + +-- compile the source file +function compile(self, sourcefile, objectfile, dependinfo, flags, opt) + os.mkdir(path.directory(objectfile)) + local depfile = dependinfo and os.tmpfile() or nil + try + { + function () + local compflags = flags + if depfile then + compflags = table.join(compflags, "-ppd=" .. depfile) + end + local outdata, errdata = os.iorunv(compargv(self, sourcefile, objectfile, compflags)) + return (outdata or "") .. (errdata or "") + end, + catch + { + function (errors) + + -- try removing the old object file for forcing to rebuild this source file + os.tryrm(objectfile) + + -- find the start line of error + local lines = tostring(errors):split("\n") + local start = 0 + for index, line in ipairs(lines) do + if line:find("error:", 1, true) or line:find("错误:", 1, true) then + start = index + break + end + end + + -- get 16 lines of errors + if start > 0 or not option.get("verbose") then + if start == 0 then start = 1 end + errors = table.concat(table.slice(lines, start, start + ((#lines - start > 16) and 16 or (#lines - start))), "\n") + end + + -- raise compiling errors + raise(errors) + end + }, + finally + { + function (ok, warnings) + + -- print some warnings + if warnings and #warnings > 0 and policy.build_warnings(opt) then + if progress.showing_without_scroll() then + print("") + end + cprint("${color.warning}%s", table.concat(table.slice(warnings:split('\n'), 1, 8), '\n')) + end + + -- generate the dependent includes + if depfile and os.isfile(depfile) then + if dependinfo then + dependinfo.depfiles_format = "cl6x" + dependinfo.depfiles = io.readfile(depfile, {continuation = "\\"}) + end + + -- remove the temporary dependent file + os.tryrm(depfile) + end + end + } + } +end + + diff --git a/tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x/has_flags.lua b/tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x/has_flags.lua new file mode 100644 index 000000000..a5f3f4b87 --- /dev/null +++ b/tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x/has_flags.lua @@ -0,0 +1,121 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, TBOOX Open Source Group. +-- +-- @author ruki +-- @file has_flags.lua +-- + +-- imports +import("core.cache.detectcache") +import("core.language.language") + +-- is linker? +function _islinker(flags, opt) + local toolkind = opt.toolkind or "" + return toolkind == "ld" or toolkind == "sh" or toolkind:endswith("ld") or toolkind:endswith("sh") +end + +-- try running +function _try_running(program, argv, opt) + local errors = nil + return try { function () os.runv(program, argv, opt); return true end, catch { function (errs) errors = (errs or ""):trim() end }}, errors +end + +-- attempt to check it from known flags +function _check_from_knownargs(flags, opt, islinker) + local flag = flags[1] + if not islinker then + if flag:startswith("-D") or + flag:startswith("-U") or + flag:startswith("-I") then + return true + end + end +end + +-- attempt to check it from the argument list +function _check_from_arglist(flags, opt, islinker) + local key = "core.tools.cl6x." .. (islinker and "has_ldflags" or "has_cflags") + local flagskey = opt.program .. "_" .. (opt.programver or "") + local allflags = detectcache:get2(key, flagskey) + if not allflags then + allflags = {} + local arglist = try {function () return os.iorunv(opt.program, {"--help"}, {envs = opt.envs}) end} + if arglist then + for arg in arglist:gmatch("%s+(%-[%-%a%d]+)%s+") do + allflags[arg] = true + end + end + detectcache:set2(key, flagskey, allflags) + detectcache:save() + end + local flag = flags[1] + return allflags[flag] +end + +-- get extension +function _get_extension(opt) + -- @note we need to detect extension for ndk/clang++.exe: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated] + return (opt.program:endswith("++") or opt.flagkind == "cxxflags") and ".cpp" or (table.wrap(language.sourcekinds()[opt.toolkind or "cc"])[1] or ".c") +end + +-- try running to check flags +function _check_try_running(flags, opt, islinker) + + -- make an stub source file + local snippet = opt.snippet or "int main(int argc, char** argv)\n{return 0;}\n" + local sourcefile = os.tmpfile("cl6x_has_flags:" .. snippet) .. _get_extension(opt) + if not os.isfile(sourcefile) then + io.writefile(sourcefile, snippet) + end + + -- check flags for linker + local tmpfile = os.tmpfile() + if islinker then + return _try_running(opt.program, table.join(flags, "-z", "--output_file=" .. tmpfile, sourcefile), opt) + end + + -- check flags for compiler + -- @note we cannot use os.nuldev() as the output file, maybe run failed for some flags, e.g. --coverage + return _try_running(opt.program, table.join(flags, "-c", "--output_file=" .. tmpfile, sourcefile), opt) +end + +-- has_flags(flags)? +-- +-- @param opt the argument options, e.g. {toolname = "", program = "", programver = "", toolkind = "[cc|cxx|ld|ar|sh|gc|mm|mxx]"} +-- +-- @return true or false +-- +function main(flags, opt) + + -- is linker? + opt = opt or {} + local islinker = _islinker(flags, opt) + + -- attempt to check it from the argument list + if not opt.tryrun then + if _check_from_arglist(flags, opt, islinker) then + return true + end + if _check_from_knownargs(flags, opt, islinker) then + return true + end + end + + -- try running to check it + return _check_try_running(flags, opt, islinker) +end + diff --git a/tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x/parse_deps.lua b/tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x/parse_deps.lua new file mode 100644 index 000000000..a5d5ecd40 --- /dev/null +++ b/tests/apis/custom_toolchain/xmake/modules/core/tools/cl6x/parse_deps.lua @@ -0,0 +1,77 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, TBOOX Open Source Group. +-- +-- @author ruki +-- @file parse_deps.lua +-- + +-- imports +import("core.project.config") +import("core.project.project") +import("core.base.hashset") + +-- normailize path of a dependecy +function _normailize_dep(dep, projectdir) + -- escape characters, e.g. \#Qt.Widget_pch.h -> #Qt.Widget_pch.h + -- @see https://github.com/xmake-io/xmake/issues/4134 + -- https://github.com/xmake-io/xmake/issues/4273 + if not is_host("windows") then + dep = dep:gsub("\\(.)", "%1") + end + if path.is_absolute(dep) then + dep = path.translate(dep) + else + dep = path.absolute(dep, projectdir) + end + if dep:startswith(projectdir) then + return path.relative(dep, projectdir) + else + -- we also need to check header files outside project + -- https://github.com/xmake-io/xmake/issues/1154 + return dep + end +end + +-- parse depsfiles from string +-- +-- parse_deps(io.readfile(depfile, {continuation = "\\"})) +-- +-- eg. +-- +-- build/.objs/foo/linux/x86_64/release/src/foo.c.o: src/foo.c +-- build/.objs/foo/linux/x86_64/release/src/foo.c.o: src/foo.h +-- +-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/main.c +-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/foo.h +-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/bar.h +-- build/.objs/tests/linux/x86_64/release/src/main.c.o: src/zoo.h +-- +function main(depsdata, opt) + local results = hashset.new() + local projectdir = os.projectdir() + local line = depsdata:rtrim() -- maybe there will be an empty newline at the end. so we trim it first + local plain = {plain = true} + for _, includefile in ipairs(line:split('\n', plain)) do -- it will trim all internal spaces without `{strict = true}` + includefile = includefile:split(": ", plain)[2] + if includefile and #includefile > 0 then + includefile = _normailize_dep(includefile, projectdir) + if includefile then + results:insert(includefile) + end + end + end + return results:to_array() +end diff --git a/tests/apis/custom_toolchain/xmake/modules/detect/tools/find_ar6x.lua b/tests/apis/custom_toolchain/xmake/modules/detect/tools/find_ar6x.lua new file mode 100644 index 000000000..823a1f220 --- /dev/null +++ b/tests/apis/custom_toolchain/xmake/modules/detect/tools/find_ar6x.lua @@ -0,0 +1,58 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, TBOOX Open Source Group. +-- +-- @author ruki +-- @file find_ar6x.lua +-- + +-- imports +import("lib.detect.find_program") + +-- check +function _check(program) + + -- make a stub object file + local libraryfile = os.tmpfile() .. ".a" + local objectfile = os.tmpfile() .. ".o" + io.writefile(objectfile, "") + + -- archive it + os.execv(program, {"-r", libraryfile, objectfile}) + + -- remove files + os.rm(objectfile) + os.rm(libraryfile) +end + +-- find ar +-- +-- @param opt the argument options, e.g. {version = true} +-- +-- @return program, version +-- +-- @code +-- +-- local ar = find_ar6x() +-- local ar, version = find_ar6x({program = "xcrun -sdk macosx g++", version = true}) +-- +-- @endcode +-- +function main(opt) + opt = opt or {} + opt.check = opt.check or _check + return find_program(opt.program or "ar6x", opt) +end + diff --git a/tests/apis/custom_toolchain/xmake/modules/detect/tools/find_cl6x.lua b/tests/apis/custom_toolchain/xmake/modules/detect/tools/find_cl6x.lua new file mode 100644 index 000000000..c961326ad --- /dev/null +++ b/tests/apis/custom_toolchain/xmake/modules/detect/tools/find_cl6x.lua @@ -0,0 +1,48 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, TBOOX Open Source Group. +-- +-- @author ruki +-- @file find_cl6x.lua +-- + +-- imports +import("lib.detect.find_program") +import("lib.detect.find_programver") + +-- find cl6x +-- +-- @param opt the argument options, e.g. {version = true} +-- +-- @return program, version +-- +-- @code +-- +-- local cl6x = find_cl6x() +-- local cl6x, version = find_cl6x({program = "cl6x", version = true}) +-- +-- @endcode +-- +function main(opt) + opt = opt or {} + opt.check = "--help" + opt.command = "--help" + local program = find_program(opt.program or "cl6x", opt) + local version = nil + if program and opt.version then + version = find_programver(program, opt) + end + return program, version +end diff --git a/tests/apis/custom_toolchain/xmake/toolchains/my-c6000/xmake.lua b/tests/apis/custom_toolchain/xmake/toolchains/my-c6000/xmake.lua new file mode 100644 index 000000000..2de2275a7 --- /dev/null +++ b/tests/apis/custom_toolchain/xmake/toolchains/my-c6000/xmake.lua @@ -0,0 +1,20 @@ +toolchain("my-c6000") + set_kind("standalone") + set_homepage("https://www.ti.com") + set_description("TI-CGT C6000 compiler") + + set_toolset("cc", "cl6x") + set_toolset("cxx", "cl6x") + set_toolset("ld", "cl6x") + set_toolset("sh", "cl6x") + set_toolset("ar", "ar6x") + set_toolset("strip", "strip6x") + set_toolset("as", "cl6x") + + on_check(function (toolchain) + return import("lib.detect.find_tool")("cl6x") + end) + + on_load(function (toolchain) + toolchain:add("cxflags", "-Dxxx") + end) diff --git a/tests/apis/set_toolchains/src/foo.cpp b/tests/apis/set_toolchains/src/foo.cpp new file mode 100644 index 000000000..1a1fb3425 --- /dev/null +++ b/tests/apis/set_toolchains/src/foo.cpp @@ -0,0 +1,5 @@ +#include "foo.h" + +int add(int a, int b) { + return a + b; +} diff --git a/tests/apis/set_toolchains/src/foo.h b/tests/apis/set_toolchains/src/foo.h new file mode 100644 index 000000000..d2506bca9 --- /dev/null +++ b/tests/apis/set_toolchains/src/foo.h @@ -0,0 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + +int add(int a, int b); + +#ifdef __cplusplus +} +#endif diff --git a/tests/apis/set_toolchains/src/interface.cpp b/tests/apis/set_toolchains/src/interface.cpp deleted file mode 100644 index 598d07560..000000000 --- a/tests/apis/set_toolchains/src/interface.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "interface.h" - -int add(int a, int b) -{ - return a + b; -} diff --git a/tests/apis/set_toolchains/src/interface.h b/tests/apis/set_toolchains/src/interface.h deleted file mode 100644 index 4a41e9597..000000000 --- a/tests/apis/set_toolchains/src/interface.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifdef __cplusplus -extern "C" { -#endif - -/*! calculate add(a, b) - * - * @param a the first argument - * @param b the second argument - * - * @return the result - */ -int add(int a, int b); - -#ifdef __cplusplus -} -#endif diff --git a/tests/apis/set_toolchains/src/test.cpp b/tests/apis/set_toolchains/src/test.cpp index 72e03272b..ed1924789 100644 --- a/tests/apis/set_toolchains/src/test.cpp +++ b/tests/apis/set_toolchains/src/test.cpp @@ -1,10 +1,9 @@ -#include "interface.h" +#include "foo.h" #include <iostream> using namespace std; -int main(int argc, char** argv) -{ - cout << "add(1, 2) = " << add(1, 2) << endl; +int main(int argc, char** argv) { + cout << "add(1, 2) = " << add(1, 2) << endl; return 0; } diff --git a/tests/apis/set_toolchains/xmake.lua b/tests/apis/set_toolchains/xmake.lua index 9db80f107..75f866fbd 100644 --- a/tests/apis/set_toolchains/xmake.lua +++ b/tests/apis/set_toolchains/xmake.lua @@ -1,10 +1,6 @@ --- define toolchain toolchain("myclang") - - -- mark as standalone toolchain set_kind("standalone") - -- set toolset set_toolset("cc", "clang") set_toolset("cxx", "clang", "clang++") set_toolset("ld", "clang++", "clang") @@ -23,7 +19,7 @@ add_rules("mode.debug", "mode.release") target("test") set_kind("static") - add_files("src/interface.cpp") + add_files("src/foo.cpp") set_toolset("ar", "ar") target("demo") |
