diff options
| author | ruki <[email protected]> | 2023-04-25 11:24:08 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-04-25 11:24:08 +0800 |
| commit | 1b4a1acc56cc0d80efa53ad836b4e7263f198803 (patch) | |
| tree | 9f412f7c1382fc8c65fa0fb620c3c91300c3a4c9 | |
| parent | 8b0dd0af6d17b5b8aca36ff64c062fe567ac8ca4 (diff) | |
| parent | cd4f63cf3bc4cdad108caf23edc59a4007a927d7 (diff) | |
Merge pull request #3665 from xmake-io/cmakelists
Improve cmake generator for rule
| -rw-r--r-- | xmake/actions/build/kinds/object.lua | 75 | ||||
| -rw-r--r-- | xmake/modules/private/utils/rule_groups.lua | 94 | ||||
| -rw-r--r-- | xmake/plugins/project/cmake/cmakelists.lua | 138 | ||||
| -rw-r--r-- | xmake/rules/lex_yacc/lex/xmake.lua | 3 |
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") |
