diff options
| author | ruki <[email protected]> | 2021-10-18 21:03:03 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-10-18 21:03:03 +0800 |
| commit | 0f72e5b597abf1f3caff40cc1e9b15f68212ad0e (patch) | |
| tree | 616b20f34a515e45bcf5d14fad7b903006489454 | |
| parent | 2c018854833aa388bb16580f7d61646e90ce4bda (diff) | |
| parent | 7e6fba5fe7662b4e58ce150aeab17c70b6b12254 (diff) | |
Merge pull request #1749 from xmake-io/unit_build
Support Unity build
30 files changed, 422 insertions, 4 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 09b60b8ae..89d1a64aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * Add gcc-8, gcc-9, gcc-10, gcc-11 toolchains * [#1623](https://github.com/xmake-io/xmake/issues/1632): Support find_package from cmake * [#1747](https://github.com/xmake-io/xmake/issues/1747): Add `set_kind("headeronly")` for target to install files for headeronly library +* [#1019](https://github.com/xmake-io/xmake/issues/1019): Support Unity build ### Changes @@ -1110,6 +1111,7 @@ * 添加 gcc-8, gcc-9, gcc-10, gcc-11 工具链 * [#1623](https://github.com/xmake-io/xmake/issues/1632): 支持 find_package 从 cmake 查找包 * [#1747](https://github.com/xmake-io/xmake/issues/1747): 添加 `set_kind("headeronly")` 更好的处理 headeronly 库的安装 +* [#1019](https://github.com/xmake-io/xmake/issues/1019): 支持 Unity build ### 改进 diff --git a/tests/projects/c++/unity_build/src/bar/test4.cpp b/tests/projects/c++/unity_build/src/bar/test4.cpp new file mode 100644 index 000000000..8fe732964 --- /dev/null +++ b/tests/projects/c++/unity_build/src/bar/test4.cpp @@ -0,0 +1,12 @@ + +// main.cpp +#include "header.h" + +namespace MY_UNITY_ID { + int i = 42; +} + +int test4() +{ + return MY_UNITY_ID::i; +} diff --git a/tests/projects/c++/unity_build/src/bar/test5.cpp b/tests/projects/c++/unity_build/src/bar/test5.cpp new file mode 100644 index 000000000..afff0b46c --- /dev/null +++ b/tests/projects/c++/unity_build/src/bar/test5.cpp @@ -0,0 +1,13 @@ + +// main.cpp +#include "header.h" + +namespace MY_UNITY_ID { + int i = 42; +} + +int test5() +{ + return MY_UNITY_ID::i; +} + diff --git a/tests/projects/c++/unity_build/src/bar/test6.cpp b/tests/projects/c++/unity_build/src/bar/test6.cpp new file mode 100644 index 000000000..efbd7c6c1 --- /dev/null +++ b/tests/projects/c++/unity_build/src/bar/test6.cpp @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test6() +{ + return 0; +} diff --git a/tests/projects/c++/unity_build/src/foo/test.cpp b/tests/projects/c++/unity_build/src/foo/test.cpp new file mode 100644 index 000000000..e9d6c83d9 --- /dev/null +++ b/tests/projects/c++/unity_build/src/foo/test.cpp @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test() +{ + return 0; +} diff --git a/tests/projects/c++/unity_build/src/foo/test2.cpp b/tests/projects/c++/unity_build/src/foo/test2.cpp new file mode 100644 index 000000000..596359cd2 --- /dev/null +++ b/tests/projects/c++/unity_build/src/foo/test2.cpp @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test2() +{ + return 0; +} diff --git a/tests/projects/c++/unity_build/src/header.h b/tests/projects/c++/unity_build/src/header.h new file mode 100644 index 000000000..affda55ca --- /dev/null +++ b/tests/projects/c++/unity_build/src/header.h @@ -0,0 +1,27 @@ +// header.h +#ifndef HEADER_H +#define HEADER_H + +#include <algorithm> +#include <deque> +#include <iostream> +#include <map> +#include <memory> +#include <set> +//#include <thread> +#include <utility> +#include <vector> +#include <string> +#include <queue> +#include <cstdlib> +#include <utility> +#include <exception> +#include <list> +#include <stack> +#include <complex> +#include <fstream> +#include <cstdio> +#include <iomanip> + +#endif + diff --git a/tests/projects/c++/unity_build/src/header2.h b/tests/projects/c++/unity_build/src/header2.h new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/projects/c++/unity_build/src/header2.h diff --git a/tests/projects/c++/unity_build/src/main.cpp b/tests/projects/c++/unity_build/src/main.cpp new file mode 100644 index 000000000..27d41ee50 --- /dev/null +++ b/tests/projects/c++/unity_build/src/main.cpp @@ -0,0 +1,8 @@ +#include "header.h" + +int main(int argc, char** argv) +{ + std::string s("xmake"); + printf("hello %s!\n", s.c_str()); + return 0; +} diff --git a/tests/projects/c++/unity_build/src/test.c b/tests/projects/c++/unity_build/src/test.c new file mode 100644 index 000000000..7f0aa2bf4 --- /dev/null +++ b/tests/projects/c++/unity_build/src/test.c @@ -0,0 +1,4 @@ + +void test_c(void) +{ +} diff --git a/tests/projects/c++/unity_build/src/test7.cpp b/tests/projects/c++/unity_build/src/test7.cpp new file mode 100644 index 000000000..24aeff619 --- /dev/null +++ b/tests/projects/c++/unity_build/src/test7.cpp @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test7() +{ + return 0; +} diff --git a/tests/projects/c++/unity_build/src/test8.cpp b/tests/projects/c++/unity_build/src/test8.cpp new file mode 100644 index 000000000..6ad5680a6 --- /dev/null +++ b/tests/projects/c++/unity_build/src/test8.cpp @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test8() +{ + return 0; +} diff --git a/tests/projects/c++/unity_build/test.lua b/tests/projects/c++/unity_build/test.lua new file mode 100644 index 000000000..b76241be2 --- /dev/null +++ b/tests/projects/c++/unity_build/test.lua @@ -0,0 +1,6 @@ +-- main entry +function main(t) + + -- build project + t:build() +end diff --git a/tests/projects/c++/unity_build/xmake.lua b/tests/projects/c++/unity_build/xmake.lua new file mode 100644 index 000000000..a881c5c36 --- /dev/null +++ b/tests/projects/c++/unity_build/xmake.lua @@ -0,0 +1,9 @@ +target("test") + set_kind("binary") + add_includedirs("src") + add_rules("c++.unity_build", {batchsize = 2, uniqueid = "MY_UNITY_ID"}) + add_files("src/*.c", "src/*.cpp") + add_files("src/foo/*.cpp", {unity_group = "foo"}) + add_files("src/bar/*.cpp", {unity_group = "bar"}) + + diff --git a/tests/projects/c/unity_build/src/bar/test4.c b/tests/projects/c/unity_build/src/bar/test4.c new file mode 100644 index 000000000..a92803eb7 --- /dev/null +++ b/tests/projects/c/unity_build/src/bar/test4.c @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test4() +{ + return 0; +} diff --git a/tests/projects/c/unity_build/src/bar/test5.c b/tests/projects/c/unity_build/src/bar/test5.c new file mode 100644 index 000000000..2a3e7066c --- /dev/null +++ b/tests/projects/c/unity_build/src/bar/test5.c @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test5() +{ + return 0; +} diff --git a/tests/projects/c/unity_build/src/foo/test1.c b/tests/projects/c/unity_build/src/foo/test1.c new file mode 100644 index 000000000..e9d6c83d9 --- /dev/null +++ b/tests/projects/c/unity_build/src/foo/test1.c @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test() +{ + return 0; +} diff --git a/tests/projects/c/unity_build/src/foo/test2.c b/tests/projects/c/unity_build/src/foo/test2.c new file mode 100644 index 000000000..b4ce69b0f --- /dev/null +++ b/tests/projects/c/unity_build/src/foo/test2.c @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test3() +{ + return 0; +} diff --git a/tests/projects/c/unity_build/src/header.h b/tests/projects/c/unity_build/src/header.h new file mode 100644 index 000000000..29bfc5870 --- /dev/null +++ b/tests/projects/c/unity_build/src/header.h @@ -0,0 +1,10 @@ +// header.h +#ifndef HEADER_H +#define HEADER_H + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#endif + diff --git a/tests/projects/c/unity_build/src/main.c b/tests/projects/c/unity_build/src/main.c new file mode 100644 index 000000000..f0408cdf8 --- /dev/null +++ b/tests/projects/c/unity_build/src/main.c @@ -0,0 +1,7 @@ +#include "header.h" + +int main(int argc, char** argv) +{ + printf("hello xmake!\n"); + return 0; +} diff --git a/tests/projects/c/unity_build/src/test.cpp b/tests/projects/c/unity_build/src/test.cpp new file mode 100644 index 000000000..1cedddad9 --- /dev/null +++ b/tests/projects/c/unity_build/src/test.cpp @@ -0,0 +1,4 @@ +int test_cpp() +{ + return 0; +} diff --git a/tests/projects/c/unity_build/src/test2.c b/tests/projects/c/unity_build/src/test2.c new file mode 100644 index 000000000..596359cd2 --- /dev/null +++ b/tests/projects/c/unity_build/src/test2.c @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test2() +{ + return 0; +} diff --git a/tests/projects/c/unity_build/src/test6.c b/tests/projects/c/unity_build/src/test6.c new file mode 100644 index 000000000..efbd7c6c1 --- /dev/null +++ b/tests/projects/c/unity_build/src/test6.c @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test6() +{ + return 0; +} diff --git a/tests/projects/c/unity_build/src/test7.c b/tests/projects/c/unity_build/src/test7.c new file mode 100644 index 000000000..24aeff619 --- /dev/null +++ b/tests/projects/c/unity_build/src/test7.c @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test7() +{ + return 0; +} diff --git a/tests/projects/c/unity_build/src/test8.c b/tests/projects/c/unity_build/src/test8.c new file mode 100644 index 000000000..6ad5680a6 --- /dev/null +++ b/tests/projects/c/unity_build/src/test8.c @@ -0,0 +1,8 @@ + +// main.cpp +#include "header.h" + +int test8() +{ + return 0; +} diff --git a/tests/projects/c/unity_build/test.lua b/tests/projects/c/unity_build/test.lua new file mode 100644 index 000000000..b76241be2 --- /dev/null +++ b/tests/projects/c/unity_build/test.lua @@ -0,0 +1,6 @@ +-- main entry +function main(t) + + -- build project + t:build() +end diff --git a/tests/projects/c/unity_build/xmake.lua b/tests/projects/c/unity_build/xmake.lua new file mode 100644 index 000000000..89166a312 --- /dev/null +++ b/tests/projects/c/unity_build/xmake.lua @@ -0,0 +1,8 @@ +target("test") + set_kind("binary") + add_includedirs("src") + add_rules("c.unity_build", {batchsize = 2}) + add_files("src/*.c", "src/*.cpp") + add_files("src/foo/*.c", {unity_group = "foo"}) + add_files("src/bar/*.c", {unity_group = "bar"}) + diff --git a/xmake/core/project/target.lua b/xmake/core/project/target.lua index d6bba579a..08ab720c0 100644 --- a/xmake/core/project/target.lua +++ b/xmake/core/project/target.lua @@ -1688,11 +1688,7 @@ function _instance:sourcebatches() end end end - - -- cache it self._SOURCEBATCHES = sourcebatches - - -- ok? return sourcebatches, modified end diff --git a/xmake/rules/c++/unity_build/unity_build.lua b/xmake/rules/c++/unity_build/unity_build.lua new file mode 100644 index 000000000..608f79fed --- /dev/null +++ b/xmake/rules/c++/unity_build/unity_build.lua @@ -0,0 +1,139 @@ +--!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 unity_build.lua +-- + +-- imports +import("core.project.depend") + +function _merge_unityfile(target, sourcefile_unity, sourcefiles, opt) + local dependfile = target:dependfile(sourcefile_unity) + depend.on_changed(function () + + -- trace + vprint("generating.unityfile %s", sourcefile_unity) + + -- do merge + local uniqueid = target:data("unity_build.uniqueid") + local unityfile = io.open(sourcefile_unity, "w") + for _, sourcefile in ipairs(sourcefiles) do + sourcefile = path.absolute(sourcefile) + sourcefile_unity = path.absolute(sourcefile_unity) + sourcefile = path.relative(sourcefile, path.directory(sourcefile_unity)) + if uniqueid then + unityfile:print("#define %s %s", uniqueid, "unity_" .. hash.uuid():split("-", {plain = true})[1]) + end + unityfile:print("#include \"%s\"", sourcefile) + if uniqueid then + unityfile:print("#undef %s", uniqueid) + end + end + unityfile:close() + + end, {dependfile = dependfile, files = sourcefiles}) +end + +function generate_unityfiles(target, sourcebatch, opt) + local unity_batch = target:data("unity_build.unity_batch." .. sourcebatch.rulename) + if unity_batch then + for _, sourcefile_unity in ipairs(sourcebatch.sourcefiles) do + local sourceinfo = unity_batch[sourcefile_unity] + if sourceinfo then + local sourcefiles = sourceinfo.sourcefiles + if sourcefiles then + _merge_unityfile(target, sourcefile_unity, sourcefiles, opt) + end + end + end + end +end + +-- use unity build +-- +-- e.g. +-- add_rules("c++.unity_build", {batchsize = 2}) +-- add_files("src/*.c", "src/*.cpp", {unity_ignored = true}) +-- add_files("src/foo/*.c", {unity_group = "foo"}) +-- add_files("src/bar/*.c", {unity_group = "bar"}) +-- +function main(target, sourcebatch) + + -- get unit batch sources + local extraconf = target:extraconf("rules", sourcebatch.sourcekind == "cxx" and "c++.unity_build" or "c.unity_build") + local batchsize = extraconf and extraconf.batchsize + local uniqueid = extraconf and extraconf.uniqueid + local id = 1 + local count = 0 + local unity_batch = {} + local sourcefiles = {} + local objectfiles = {} + local dependfiles = {} + local sourcedir = path.join(target:autogendir({root = true}), "unity_build") + for idx, sourcefile in pairs(sourcebatch.sourcefiles) do + local sourcefile_unity + local objectfile = sourcebatch.objectfiles[idx] + local dependfile = sourcebatch.dependfiles[idx] + local fileconfig = target:fileconfig(sourcefile) + if fileconfig and fileconfig.unity_group then + sourcefile_unity = path.join(sourcedir, "unity_" .. fileconfig.unity_group .. path.extension(sourcefile)) + elseif (fileconfig and fileconfig.unity_ignored) or (batchsize and batchsize <= 1) then + -- we do not add these files to unity file + table.insert(sourcefiles, sourcefile) + table.insert(objectfiles, objectfile) + table.insert(dependfiles, dependfile) + else + if batchsize and count > batchsize then + id = id + 1 + end + sourcefile_unity = path.join(sourcedir, "unity_" .. hash.uuid(tostring(id)):split("-", {plain = true})[1] .. path.extension(sourcefile)) + count = count + 1 + end + if sourcefile_unity then + local sourceinfo = unity_batch[sourcefile_unity] + if not sourceinfo then + sourceinfo = {} + sourceinfo.objectfile = target:objectfile(sourcefile_unity) + sourceinfo.dependfile = target:dependfile(sourceinfo.objectfile) + unity_batch[sourcefile_unity] = sourceinfo + end + sourceinfo.sourcefiles = sourceinfo.sourcefiles or {} + table.insert(sourceinfo.sourcefiles, sourcefile) + end + end + + -- use unit batch + for _, sourcefile_unity in ipairs(table.orderkeys(unity_batch)) do + local sourceinfo = unity_batch[sourcefile_unity] + if #sourceinfo.sourcefiles > 1 then + table.insert(sourcefiles, sourcefile_unity) + table.insert(objectfiles, sourceinfo.objectfile) + table.insert(dependfiles, sourceinfo.dependfile) + else + table.insert(sourcefiles, sourceinfo.sourcefiles[1]) + table.insert(objectfiles, sourceinfo.objectfile) + table.insert(dependfiles, sourceinfo.dependfile) + end + end + sourcebatch.sourcefiles = sourcefiles + sourcebatch.objectfiles = objectfiles + sourcebatch.dependfiles = dependfiles + + -- save unit batch + target:data_set("unity_build.uniqueid", uniqueid) + target:data_set("unity_build.unity_batch." .. sourcebatch.rulename, unity_batch) +end diff --git a/xmake/rules/c++/unity_build/xmake.lua b/xmake/rules/c++/unity_build/xmake.lua new file mode 100644 index 000000000..e0dfa9660 --- /dev/null +++ b/xmake/rules/c++/unity_build/xmake.lua @@ -0,0 +1,63 @@ +--!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 xmake.lua +-- + +rule("c.unity_build") + after_load(function (target) + import("unity_build") + local sourcebatches = target:sourcebatches() + if sourcebatches then + local sourcebatch = sourcebatches["c.build"] + if sourcebatch then + unity_build(target, sourcebatch) + end + end + end) + before_build(function (target, opt) + import("unity_build") + local sourcebatches = target:sourcebatches() + if sourcebatches then + local sourcebatch = sourcebatches["c.build"] + if sourcebatch then + unity_build.generate_unityfiles(target, sourcebatch, opt) + end + end + end) + +rule("c++.unity_build") + after_load(function (target) + import("unity_build") + local sourcebatches = target:sourcebatches() + if sourcebatches then + local sourcebatch = sourcebatches["c++.build"] + if sourcebatch then + unity_build(target, sourcebatch) + end + end + end) + before_build(function (target, opt) + import("unity_build") + local sourcebatches = target:sourcebatches() + if sourcebatches then + local sourcebatch = sourcebatches["c++.build"] + if sourcebatch then + unity_build.generate_unityfiles(target, sourcebatch, opt) + end + end + end) |
