diff options
| author | ruki <[email protected]> | 2021-10-28 15:54:49 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-10-28 15:54:49 +0800 |
| commit | 0fcbd78cc212f820aa8c33d9cfb73f3e6018af42 (patch) | |
| tree | 9a131dd2f1db79a8f1cd94125563c71507de874a | |
| parent | 0b3057dce66dc41957de6c588d1fd2664c8de298 (diff) | |
| parent | d48ea6ae405def382ece2aa58cad9ab96d6fcd80 (diff) | |
Merge pull request #1780 from xmake-io/cmake
Add custom commands for cmake
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| -rw-r--r-- | xmake/plugins/project/cmake/cmakelists.lua | 171 | ||||
| -rw-r--r-- | xmake/plugins/project/make/makefile.lua | 6 | ||||
| -rw-r--r-- | xmake/rules/utils/bin2c/xmake.lua | 8 |
4 files changed, 173 insertions, 14 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f0821a32..42a4452ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * [#1767](https://github.com/xmake-io/xmake/issues/1767): Support Circle compiler * [#1753](https://github.com/xmake-io/xmake/issues/1753): Support armcc/armclang toolchains for Keil/MDK * [#1774](https://github.com/xmake-io/xmake/issues/1774): Add table.contains api +* [#1735](https://github.com/xmake-io/xmake/issues/1735): Add custom command in cmake generator ### Changes @@ -1125,6 +1126,7 @@ * [#1767](https://github.com/xmake-io/xmake/issues/1767): 支持 Circle 编译器 * [#1753](https://github.com/xmake-io/xmake/issues/1753): 支持 Keil/MDK 的 armcc/armclang 工具链 * [#1774](https://github.com/xmake-io/xmake/issues/1774): 添加 table.contains api +* [#1735](https://github.com/xmake-io/xmake/issues/1735): 添加自定义命令到 cmake 生成器 ### 改进 diff --git a/xmake/plugins/project/cmake/cmakelists.lua b/xmake/plugins/project/cmake/cmakelists.lua index ba1689cb1..a8b64fa95 100644 --- a/xmake/plugins/project/cmake/cmakelists.lua +++ b/xmake/plugins/project/cmake/cmakelists.lua @@ -22,7 +22,9 @@ import("core.project.project") import("core.tool.compiler") import("core.base.semver") +import("core.project.rule") import("lib.detect.find_tool") +import("private.utils.batchcmds") -- get minimal cmake version function _get_cmake_minver() @@ -146,8 +148,13 @@ end -- add target sources function _add_target_sources(cmakelists, target) cmakelists:print("target_sources(%s PRIVATE", target:name()) - for _, sourcefile in ipairs(target:sourcefiles()) do - cmakelists:print(" " .. _get_unix_path(sourcefile)) + for _, sourcebatch in pairs(target:sourcebatches()) do + local sourcekind = sourcebatch.sourcekind + if sourcekind == "cc" or sourcekind == "cxx" or sourcekind == "as" then + for _, sourcefile in ipairs(sourcebatch.sourcefiles) do + cmakelists:print(" " .. _get_unix_path(sourcefile)) + end + end end for _, headerfile in ipairs(target:headerfiles()) do cmakelists:print(" " .. _get_unix_path(headerfile)) @@ -448,24 +455,165 @@ end -- add target link options function _add_target_link_options(cmakelists, target) - local ldflags = _get_configs_from_target(target, "ldflags") - local shflags = _get_configs_from_target(target, "shflags") + local ldflags = _get_configs_from_target(target, "ldflags") + local shflags = _get_configs_from_target(target, "shflags") if #ldflags > 0 or #shflags > 0 then - local cmake_minver = _get_cmake_minver() - if cmake_minver:ge("3.13.0") then - cmakelists:print("target_link_options(%s PRIVATE", target:name()) - else - cmakelists:print("target_link_libraries(%s PRIVATE", target:name()) - end + local flags = {} for _, flag in ipairs(table.unique(table.join(ldflags, shflags))) do if target:linker():has_flags(flag) then + table.insert(flags, flag) + end + end + if #flags > 0 then + local cmake_minver = _get_cmake_minver() + if cmake_minver:ge("3.13.0") then + cmakelists:print("target_link_options(%s PRIVATE", target:name()) + else + cmakelists:print("target_link_libraries(%s PRIVATE", target:name()) + end + for _, flag in ipairs(flags) do cmakelists:print(" " .. flag) end + cmakelists:print(")") + end + end +end + +-- get command string +function _get_command_string(cmd) + local kind = cmd.kind + if cmd.program then + return os.args(table.join(cmd.program, cmd.argv)) + elseif kind == "cp" then + if is_subhost("windows") then + return string.format("copy /Y %s %s > NUL 2>&1", cmd.srcpath, cmd.dstpath) + else + return string.format("cp %s %s", cmd.srcpath, cmd.dstpath) + end + elseif kind == "rm" then + if is_subhost("windows") then + return string.format("del /F /Q %s > NUL 2>&1 || rmdir /S /Q %s > NUL 2>&1", cmd.filepath, cmd.filepath) + else + return string.format("rm -rf %s", cmd.filepath) + end + elseif kind == "mkdir" then + if is_subhost("windows") then + return string.format("mkdir %s > NUL 2>&1", cmd.dir) + else + return string.format("mkdir -p %s", cmd.dir) end + elseif kind == "show" then + return string.format("echo %s", cmd.showtext) + end +end + +-- add custom command +function _add_target_custom_command(cmakelists, target, command, suffix) + if suffix == "before" then + -- ADD_CUSTOM_COMMAND and PRE_BUILD did not work as I expected, + -- so we need use add_dependencies and fake target to support it. + -- + -- @see https://gitlab.kitware.com/cmake/cmake/-/issues/17802 + -- + local key = target:name() .. "_" .. hash.uuid():split("-", {plain = true})[1] + cmakelists:print("add_custom_command(OUTPUT output_%s", key) + cmakelists:print(" COMMAND %s", command) + cmakelists:print(" VERBATIM") + cmakelists:print(")") + cmakelists:print("add_custom_target(target_%s", key) + cmakelists:print(" DEPENDS output_%s", key) cmakelists:print(")") + cmakelists:print("add_dependencies(%s target_%s)", target:name(), key) + else + cmakelists:print("add_custom_command(TARGET %s", target:name()) + if suffix == "after" then + cmakelists:print(" POST_BUILD") + end + cmakelists:print(" COMMAND %s", command) + cmakelists:print(" VERBATIM") + cmakelists:print(")") + end +end + +-- add target custom commands for target +function _add_target_custom_commands_for_target(cmakelists, target, suffix) + for _, ruleinst in ipairs(target:orderules()) do + local scriptname = "buildcmd" .. (suffix and ("_" .. suffix) or "") + local script = ruleinst:script(scriptname) + if script then + local batchcmds_ = batchcmds.new({target = target}) + script(target, batchcmds_, {}) + if not batchcmds_:empty() then + for _, cmd in ipairs(batchcmds_:cmds()) do + local command = _get_command_string(cmd) + if command then + _add_target_custom_command(cmakelists, target, command, suffix) + end + end + end + end end end +-- add target custom commands for object rules +function _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, suffix) + + -- get rule + local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!") + local ruleinst = assert(project.rule(rulename) or rule.rule(rulename), "unknown rule: %s", rulename) + + -- generate commands for xx_buildcmd_files + local scriptname = "buildcmd_files" .. (suffix and ("_" .. suffix) or "") + local script = ruleinst:script(scriptname) + if script then + local batchcmds_ = batchcmds.new({target = target}) + script(target, batchcmds_, sourcebatch, {}) + if not batchcmds_:empty() then + for _, cmd in ipairs(batchcmds_:cmds()) do + local command = _get_command_string(cmd) + if command then + _add_target_custom_command(cmakelists, target, command, suffix) + end + end + end + end + + -- generate commands for xx_buildcmd_file + if not script then + scriptname = "buildcmd_file" .. (suffix and ("_" .. suffix) or "") + script = ruleinst:script(scriptname) + if script then + local sourcekind = sourcebatch.sourcekind + for _, sourcefile in ipairs(sourcebatch.sourcefiles) do + local batchcmds_ = batchcmds.new({target = target}) + script(target, batchcmds_, sourcefile, {}) + if not batchcmds_:empty() then + for _, cmd in ipairs(batchcmds_:cmds()) do + local command = _get_command_string(cmd) + if command then + _add_target_custom_command(cmakelists, target, command, suffix) + end + end + end + end + end + end +end + +-- add target custom commands +function _add_target_custom_commands(cmakelists, target) + _add_target_custom_commands_for_target(cmakelists, target, "before") + for _, sourcebatch in pairs(target:sourcebatches()) do + local sourcekind = sourcebatch.sourcekind + if sourcekind ~= "cc" and sourcekind ~= "cxx" and sourcekind ~= "as" then + _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, "before") + _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch) + _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, "after") + end + end + _add_target_custom_commands_for_target(cmakelists, target, "after") +end + -- TODO export target headers (deprecated) function _export_target_headers(target) local srcheaders, dstheaders = target:headers() @@ -543,6 +691,9 @@ function _add_target(cmakelists, target) -- add target link options _add_target_link_options(cmakelists, target) + -- add target custom commands + _add_target_custom_commands(cmakelists, target) + -- add target sources _add_target_sources(cmakelists, target) diff --git a/xmake/plugins/project/make/makefile.lua b/xmake/plugins/project/make/makefile.lua index 6b94cf992..f9f0581c0 100644 --- a/xmake/plugins/project/make/makefile.lua +++ b/xmake/plugins/project/make/makefile.lua @@ -33,7 +33,7 @@ end -- mkdir directory function _mkdir(makefile, dir) - if is_plat("windows") then + if is_subhost("windows") then makefile:print("\t-@mkdir %s > NUL 2>&1", dir) else makefile:print("\t@mkdir -p %s", dir) @@ -42,7 +42,7 @@ end -- copy file function _cp(makefile, sourcefile, targetfile) - if is_plat("windows") then + if is_subhost("windows") then makefile:print("\t@copy /Y %s %s > NUL 2>&1", sourcefile, targetfile) else makefile:print("\t@cp %s %s", sourcefile, targetfile) @@ -51,7 +51,7 @@ end -- try to remove the given file or directory function _tryrm(makefile, filedir) - if is_plat("windows") then + if is_subhost("windows") then -- we attempt to delete it as file first, we remove it as directory if failed makefile:print("\t@del /F /Q %s > NUL 2>&1 || rmdir /S /Q %s > NUL 2>&1", filedir, filedir) else diff --git a/xmake/rules/utils/bin2c/xmake.lua b/xmake/rules/utils/bin2c/xmake.lua index 5110ea2fd..81e042c41 100644 --- a/xmake/rules/utils/bin2c/xmake.lua +++ b/xmake/rules/utils/bin2c/xmake.lua @@ -20,12 +20,18 @@ rule("utils.bin2c") set_extensions(".bin") + on_load(function (target) + local headerdir = path.join(target:autogendir(), "rules", "c++", "bin2c") + if not os.isdir(headerdir) then + os.mkdir(headerdir) + end + target:add("includedirs", headerdir) + end) before_buildcmd_file(function (target, batchcmds, sourcefile_bin, opt) -- get header file local headerdir = path.join(target:autogendir(), "rules", "c++", "bin2c") local headerfile = path.join(headerdir, path.filename(sourcefile_bin) .. ".h") - target:add("includedirs", headerdir) -- add commands batchcmds:show_progress(opt.progress, "${color.build.object}generating.bin2c %s", sourcefile_bin) |
