summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2023-04-25 11:24:08 +0800
committerGitHub <[email protected]>2023-04-25 11:24:08 +0800
commit1b4a1acc56cc0d80efa53ad836b4e7263f198803 (patch)
tree9f412f7c1382fc8c65fa0fb620c3c91300c3a4c9
parent8b0dd0af6d17b5b8aca36ff64c062fe567ac8ca4 (diff)
parentcd4f63cf3bc4cdad108caf23edc59a4007a927d7 (diff)
Merge pull request #3665 from xmake-io/cmakelists
Improve cmake generator for rule
-rw-r--r--xmake/actions/build/kinds/object.lua75
-rw-r--r--xmake/modules/private/utils/rule_groups.lua94
-rw-r--r--xmake/plugins/project/cmake/cmakelists.lua138
-rw-r--r--xmake/rules/lex_yacc/lex/xmake.lua3
4 files changed, 215 insertions, 95 deletions
diff --git a/xmake/actions/build/kinds/object.lua b/xmake/actions/build/kinds/object.lua
index 05fdc939c..df24db2cb 100644
--- a/xmake/actions/build/kinds/object.lua
+++ b/xmake/actions/build/kinds/object.lua
@@ -25,30 +25,7 @@ import("core.project.config")
import("core.project.project")
import("private.async.runjobs")
import("private.utils.batchcmds")
-
--- get rule
--- @note we need get rule from target first, because we maybe will inject and replace builtin rule in target
-function _get_rule(target, rulename)
- local ruleinst = assert(target:rule(rulename) or project.rule(rulename) or rule.rule(rulename), "unknown rule: %s", rulename)
- return ruleinst
-end
-
--- get max depth of rule
-function _get_rule_max_depth(target, ruleinst, depth)
- local max_depth = depth
- for _, depname in ipairs(ruleinst:get("deps")) do
- local dep = _get_rule(target, depname)
- local dep_depth = depth
- if ruleinst:extraconf("deps", depname, "order") then
- dep_depth = dep_depth + 1
- end
- local cur_depth = _get_rule_max_depth(target, dep, dep_depth)
- if cur_depth > max_depth then
- max_depth = cur_depth
- end
- end
- return max_depth
-end
+import("private.utils.rule_groups")
-- has scripts for the custom rule
function _has_scripts_for_rule(ruleinst, suffix)
@@ -114,7 +91,7 @@ function _add_batchjobs_for_rule(batchjobs, rootjob, target, sourcebatch, suffix
-- get rule
local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!")
- local ruleinst = _get_rule(target, rulename)
+ local ruleinst = rule_groups.get_rule(target, rulename)
-- add batch jobs for xx_build_files
local scriptname = "build_files" .. (suffix and ("_" .. suffix) or "")
@@ -186,7 +163,7 @@ function _add_batchjobs_for_target(batchjobs, rootjob, target, sourcebatch, suff
--
local rulename = sourcebatch.rulename
if rulename then
- local ruleinst = _get_rule(target, rulename)
+ local ruleinst = rule_groups.get_rule(target, rulename)
if not ruleinst:script("build_file") and
not ruleinst:script("build_files") then
return
@@ -234,55 +211,11 @@ function _add_batchjobs_for_group(batchjobs, rootjob, target, group, suffix)
end
end
--- build sourcebatch groups for target
-function _build_sourcebatch_groups_for_target(groups, target, sourcebatches)
- local group = groups[1]
- for _, sourcebatch in pairs(sourcebatches) do
- local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!")
- local item = group[rulename] or {}
- item.target = target
- item.sourcebatch = sourcebatch
- group[rulename] = item
- end
-end
-
--- build sourcebatch groups for rules
-function _build_sourcebatch_groups_for_rules(groups, target, sourcebatches)
- for _, sourcebatch in pairs(sourcebatches) do
- local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!")
- local ruleinst = _get_rule(target, rulename)
- local depth = _get_rule_max_depth(target, ruleinst, 1)
- local group = groups[depth]
- if group == nil then
- group = {}
- groups[depth] = group
- end
- local item = group[rulename] or {}
- item.rule = ruleinst
- item.sourcebatch = sourcebatch
- group[rulename] = item
- end
-end
-
--- build sourcebatch groups by rule dependencies order, e.g. `add_deps("qt.ui", {order = true})`
---
--- @see https://github.com/xmake-io/xmake/issues/2814
---
-function _build_sourcebatch_groups(target, sourcebatches)
- local groups = {{}}
- _build_sourcebatch_groups_for_target(groups, target, sourcebatches)
- _build_sourcebatch_groups_for_rules(groups, target, sourcebatches)
- if #groups > 0 then
- groups = table.reverse(groups)
- end
- return groups
-end
-
-- add batch jobs for building source files
function add_batchjobs_for_sourcefiles(batchjobs, rootjob, target, sourcebatches)
-- build sourcebatch groups first
- local groups = _build_sourcebatch_groups(target, sourcebatches)
+ local groups = rule_groups.build_sourcebatch_groups(target, sourcebatches)
-- add batch jobs for build_after
local groups_root
diff --git a/xmake/modules/private/utils/rule_groups.lua b/xmake/modules/private/utils/rule_groups.lua
new file mode 100644
index 000000000..f8f8181ec
--- /dev/null
+++ b/xmake/modules/private/utils/rule_groups.lua
@@ -0,0 +1,94 @@
+--!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 rule_groups.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.project.rule")
+import("core.project.config")
+import("core.project.project")
+
+-- get rule
+-- @note we need get rule from target first, because we maybe will inject and replace builtin rule in target
+function get_rule(target, rulename)
+ local ruleinst = assert(target:rule(rulename) or project.rule(rulename) or rule.rule(rulename), "unknown rule: %s", rulename)
+ return ruleinst
+end
+
+-- get max depth of rule
+function _get_rule_max_depth(target, ruleinst, depth)
+ local max_depth = depth
+ for _, depname in ipairs(ruleinst:get("deps")) do
+ local dep = get_rule(target, depname)
+ local dep_depth = depth
+ if ruleinst:extraconf("deps", depname, "order") then
+ dep_depth = dep_depth + 1
+ end
+ local cur_depth = _get_rule_max_depth(target, dep, dep_depth)
+ if cur_depth > max_depth then
+ max_depth = cur_depth
+ end
+ end
+ return max_depth
+end
+
+-- build sourcebatch groups for target
+function _build_sourcebatch_groups_for_target(groups, target, sourcebatches)
+ local group = groups[1]
+ for _, sourcebatch in pairs(sourcebatches) do
+ local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!")
+ local item = group[rulename] or {}
+ item.target = target
+ item.sourcebatch = sourcebatch
+ group[rulename] = item
+ end
+end
+
+-- build sourcebatch groups for rules
+function _build_sourcebatch_groups_for_rules(groups, target, sourcebatches)
+ for _, sourcebatch in pairs(sourcebatches) do
+ local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!")
+ local ruleinst = get_rule(target, rulename)
+ local depth = _get_rule_max_depth(target, ruleinst, 1)
+ local group = groups[depth]
+ if group == nil then
+ group = {}
+ groups[depth] = group
+ end
+ local item = group[rulename] or {}
+ item.rule = ruleinst
+ item.sourcebatch = sourcebatch
+ group[rulename] = item
+ end
+end
+
+-- build sourcebatch groups by rule dependencies order, e.g. `add_deps("qt.ui", {order = true})`
+--
+-- @see https://github.com/xmake-io/xmake/issues/2814
+--
+function build_sourcebatch_groups(target, sourcebatches)
+ local groups = {{}}
+ _build_sourcebatch_groups_for_target(groups, target, sourcebatches)
+ _build_sourcebatch_groups_for_rules(groups, target, sourcebatches)
+ if #groups > 0 then
+ groups = table.reverse(groups)
+ end
+ return groups
+end
+
diff --git a/xmake/plugins/project/cmake/cmakelists.lua b/xmake/plugins/project/cmake/cmakelists.lua
index 07e8a8749..a878ceeb9 100644
--- a/xmake/plugins/project/cmake/cmakelists.lua
+++ b/xmake/plugins/project/cmake/cmakelists.lua
@@ -28,6 +28,7 @@ import("core.base.hashset")
import("core.project.rule")
import("lib.detect.find_tool")
import("private.utils.batchcmds")
+import("private.utils.rule_groups")
-- get minimal cmake version
function _get_cmake_minver()
@@ -195,6 +196,55 @@ function _get_flags_from_fileconfig(fileconfig, outputdir, name)
end
end
+-- get flags from target
+-- @see https://github.com/xmake-io/xmake/issues/3594
+function _get_flags_from_target(target, flagkind)
+ local flags = _get_configs_from_target(target, flagkind)
+ local extraconf = target:extraconf(flagkind)
+ local sourcekind
+ if flagkind == "cflags" then
+ sourcekind = "cc"
+ elseif flagkind == "cxxflags" or flagkind == "cxflags" then
+ sourcekind = "cxx"
+ elseif flagkind == "asflags" then
+ sourcekind = "as"
+ elseif flagkind == "cuflags" then
+ sourcekind = "cu"
+ else
+ raise("unknown flag kind %s", flagkind)
+ end
+ local toolinst = target:compiler(sourcekind)
+
+ -- does this flag belong to this tool?
+ -- @see https://github.com/xmake-io/xmake/issues/3022
+ --
+ -- e.g.
+ -- for all: add_cxxflags("-g")
+ -- only for clang: add_cxxflags("clang::-stdlib=libc++")
+ -- only for clang and multiple flags: add_cxxflags("-stdlib=libc++", "-DFOO", {tools = "clang"})
+ --
+ local result = {}
+ for _, flag in ipairs(flags) do
+ local for_this_tool = true
+ local flagconf = extraconf and extraconf[flag]
+ if type(flag) == "string" and flag:find("::", 1, true) then
+ for_this_tool = false
+ local splitinfo = flag:split("::", {plain = true})
+ local toolname = splitinfo[1]
+ if toolname == toolinst:name() then
+ flag = splitinfo[2]
+ for_this_tool = true
+ end
+ elseif flagconf and flagconf.tools then
+ for_this_tool = table.contains(table.wrap(flagconf.tools), toolinst:name())
+ end
+ if for_this_tool then
+ table.insert(result, flag)
+ end
+ end
+ return result
+end
+
-- add project info
function _add_project(cmakelists, languages, outputdir)
@@ -538,10 +588,10 @@ end
-- add target compile options
function _add_target_compile_options(cmakelists, target, outputdir)
- local cflags = _get_configs_from_target(target, "cflags")
- local cxflags = _get_configs_from_target(target, "cxflags")
- local cxxflags = _get_configs_from_target(target, "cxxflags")
- local cuflags = _get_configs_from_target(target, "cuflags")
+ local cflags = _get_flags_from_target(target, "cflags")
+ local cxflags = _get_flags_from_target(target, "cxflags")
+ local cxxflags = _get_flags_from_target(target, "cxxflags")
+ local cuflags = _get_flags_from_target(target, "cuflags")
if #cflags > 0 or #cxflags > 0 or #cxxflags > 0 or #cuflags > 0 then
cmakelists:print("target_compile_options(%s PRIVATE", target:name())
for _, flag in ipairs(_translate_flags(cflags, outputdir)) do
@@ -894,7 +944,10 @@ function _get_command_string(cmd, outputdir)
end
-- add target custom commands for batchcmds
-function _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir, suffix, batchcmds)
+function _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir, suffix, cmds)
+ if #cmds == 0 then
+ return
+ end
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.
@@ -903,7 +956,7 @@ function _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir
--
local key = target:name() .. "_" .. hash.uuid():split("-", {plain = true})[1]
cmakelists:print("add_custom_command(OUTPUT output_%s", key)
- for _, cmd in ipairs(batchcmds:cmds()) do
+ for _, cmd in ipairs(cmds) do
local command = _get_command_string(cmd, outputdir)
if command then
cmakelists:print(" COMMAND %s", command)
@@ -915,12 +968,10 @@ function _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir
cmakelists:print(" DEPENDS output_%s", key)
cmakelists:print(")")
cmakelists:print("add_dependencies(%s target_%s)", target:name(), key)
- else
+ elseif suffix == "after" then
cmakelists:print("add_custom_command(TARGET %s", target:name())
- if suffix == "after" then
- cmakelists:print(" POST_BUILD")
- end
- for _, cmd in ipairs(batchcmds:cmds()) do
+ cmakelists:print(" POST_BUILD")
+ for _, cmd in ipairs(cmds) do
local command = _get_command_string(cmd, outputdir)
if command then
cmakelists:print(" COMMAND %s", command)
@@ -932,7 +983,7 @@ function _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir
end
-- add target custom commands for target
-function _add_target_custom_commands_for_target(cmakelists, target, outputdir, suffix)
+function _add_target_custom_commands_for_target(cmakelists, target, cmds, suffix)
for _, ruleinst in ipairs(target:orderules()) do
local scriptname = "buildcmd" .. (suffix and ("_" .. suffix) or "")
local script = ruleinst:script(scriptname)
@@ -940,14 +991,14 @@ function _add_target_custom_commands_for_target(cmakelists, target, outputdir, s
local batchcmds_ = batchcmds.new({target = target})
script(target, batchcmds_, {})
if not batchcmds_:empty() then
- _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir, suffix, batchcmds_)
+ table.join2(cmds, batchcmds_:cmds())
end
end
end
end
-- add target custom commands for object rules
-function _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, outputdir, suffix)
+function _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, cmds, suffix)
-- get rule
local rulename = assert(sourcebatch.rulename, "unknown rule for sourcebatch!")
@@ -960,7 +1011,7 @@ function _add_target_custom_commands_for_objectrules(cmakelists, target, sourceb
local batchcmds_ = batchcmds.new({target = target})
script(target, batchcmds_, sourcebatch, {})
if not batchcmds_:empty() then
- _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir, suffix, batchcmds_)
+ table.join2(cmds, batchcmds_:cmds())
end
end
@@ -974,24 +1025,65 @@ function _add_target_custom_commands_for_objectrules(cmakelists, target, sourceb
local batchcmds_ = batchcmds.new({target = target})
script(target, batchcmds_, sourcefile, {})
if not batchcmds_:empty() then
- _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir, suffix, batchcmds_)
+ table.join2(cmds, batchcmds_:cmds())
end
end
end
end
end
+function _add_batchjobs_for_group(batchjobs, rootjob, target, group, suffix)
+ for _, item in pairs(group) do
+ local sourcebatch = item.sourcebatch
+ if item.target then
+ _add_batchjobs_for_target(batchjobs, rootjob, target, sourcebatch, suffix)
+ end
+ -- override on_xxx script in target? we need ignore rule scripts
+ if item.rule and (suffix or not rule_groups.has_scripts_for_target(target, suffix)) then
+ _add_batchjobs_for_rule(batchjobs, rootjob, target, sourcebatch, suffix)
+ end
+ end
+end
-- add target custom commands
function _add_target_custom_commands(cmakelists, target, outputdir)
- _add_target_custom_commands_for_target(cmakelists, target, outputdir, "before")
- for _, sourcebatch in table.orderpairs(target:sourcebatches()) do
- if not _sourcebatch_is_built(sourcebatch) then
- _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, outputdir, "before")
- _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, outputdir)
- _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, outputdir, "after")
+
+ -- build sourcebatch groups first
+ local groups = rule_groups.build_sourcebatch_groups(target, target:sourcebatches())
+
+ -- add before commands
+ -- we use irpairs(groups), because the last group that should be given the highest priority.
+ local cmds_before = {}
+ _add_target_custom_commands_for_target(cmakelists, target, cmds_before, "before")
+ for idx, group in irpairs(groups) do
+ for _, item in pairs(group) do
+ -- buildcmd scripts are always in rule, so we need ignore target item (item.target).
+ local sourcebatch = item.sourcebatch
+ if item.rule then
+ if not _sourcebatch_is_built(sourcebatch) then
+ _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, cmds_before, "before")
+ -- rule.on_buildcmd_files should also be executed before building the target, as cmake PRE_BUILD does not work.
+ _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, cmds_before)
+ end
+ end
+ end
+ end
+ _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir, "before", cmds_before)
+
+ -- add after commands
+ local cmds_after = {}
+ for idx, group in irpairs(groups) do
+ for _, item in pairs(group) do
+ -- buildcmd scripts are always in rule, so we need ignore target item (item.target).
+ local sourcebatch = item.sourcebatch
+ if item.rule then
+ if not _sourcebatch_is_built(sourcebatch) then
+ _add_target_custom_commands_for_objectrules(cmakelists, target, sourcebatch, cmds_after, "after")
+ end
+ end
end
end
- _add_target_custom_commands_for_target(cmakelists, target, outputdir, "after")
+ _add_target_custom_commands_for_target(cmakelists, target, cmds_after, "after")
+ _add_target_custom_commands_for_batchcmds(cmakelists, target, outputdir, "after", cmds_after)
end
-- TODO export target headers (deprecated)
diff --git a/xmake/rules/lex_yacc/lex/xmake.lua b/xmake/rules/lex_yacc/lex/xmake.lua
index 96daade4f..3ee16b7f4 100644
--- a/xmake/rules/lex_yacc/lex/xmake.lua
+++ b/xmake/rules/lex_yacc/lex/xmake.lua
@@ -21,8 +21,9 @@
-- define rule: lex
rule("lex")
add_deps("c++")
+ add_deps("yacc", {order = true})
set_extensions(".l", ".ll")
- on_buildcmd_file(function (target, batchcmds, sourcefile_lex, opt)
+ before_buildcmd_file(function (target, batchcmds, sourcefile_lex, opt)
-- get lex
import("lib.detect.find_tool")