summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2021-10-28 15:54:49 +0800
committerGitHub <[email protected]>2021-10-28 15:54:49 +0800
commit0fcbd78cc212f820aa8c33d9cfb73f3e6018af42 (patch)
tree9a131dd2f1db79a8f1cd94125563c71507de874a
parent0b3057dce66dc41957de6c588d1fd2664c8de298 (diff)
parentd48ea6ae405def382ece2aa58cad9ab96d6fcd80 (diff)
Merge pull request #1780 from xmake-io/cmake
Add custom commands for cmake
-rw-r--r--CHANGELOG.md2
-rw-r--r--xmake/plugins/project/cmake/cmakelists.lua171
-rw-r--r--xmake/plugins/project/make/makefile.lua6
-rw-r--r--xmake/rules/utils/bin2c/xmake.lua8
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)