summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2021-10-18 21:03:03 +0800
committerGitHub <[email protected]>2021-10-18 21:03:03 +0800
commit0f72e5b597abf1f3caff40cc1e9b15f68212ad0e (patch)
tree616b20f34a515e45bcf5d14fad7b903006489454
parent2c018854833aa388bb16580f7d61646e90ce4bda (diff)
parent7e6fba5fe7662b4e58ce150aeab17c70b6b12254 (diff)
Merge pull request #1749 from xmake-io/unit_build
Support Unity build
-rw-r--r--CHANGELOG.md2
-rw-r--r--tests/projects/c++/unity_build/src/bar/test4.cpp12
-rw-r--r--tests/projects/c++/unity_build/src/bar/test5.cpp13
-rw-r--r--tests/projects/c++/unity_build/src/bar/test6.cpp8
-rw-r--r--tests/projects/c++/unity_build/src/foo/test.cpp8
-rw-r--r--tests/projects/c++/unity_build/src/foo/test2.cpp8
-rw-r--r--tests/projects/c++/unity_build/src/header.h27
-rw-r--r--tests/projects/c++/unity_build/src/header2.h0
-rw-r--r--tests/projects/c++/unity_build/src/main.cpp8
-rw-r--r--tests/projects/c++/unity_build/src/test.c4
-rw-r--r--tests/projects/c++/unity_build/src/test7.cpp8
-rw-r--r--tests/projects/c++/unity_build/src/test8.cpp8
-rw-r--r--tests/projects/c++/unity_build/test.lua6
-rw-r--r--tests/projects/c++/unity_build/xmake.lua9
-rw-r--r--tests/projects/c/unity_build/src/bar/test4.c8
-rw-r--r--tests/projects/c/unity_build/src/bar/test5.c8
-rw-r--r--tests/projects/c/unity_build/src/foo/test1.c8
-rw-r--r--tests/projects/c/unity_build/src/foo/test2.c8
-rw-r--r--tests/projects/c/unity_build/src/header.h10
-rw-r--r--tests/projects/c/unity_build/src/main.c7
-rw-r--r--tests/projects/c/unity_build/src/test.cpp4
-rw-r--r--tests/projects/c/unity_build/src/test2.c8
-rw-r--r--tests/projects/c/unity_build/src/test6.c8
-rw-r--r--tests/projects/c/unity_build/src/test7.c8
-rw-r--r--tests/projects/c/unity_build/src/test8.c8
-rw-r--r--tests/projects/c/unity_build/test.lua6
-rw-r--r--tests/projects/c/unity_build/xmake.lua8
-rw-r--r--xmake/core/project/target.lua4
-rw-r--r--xmake/rules/c++/unity_build/unity_build.lua139
-rw-r--r--xmake/rules/c++/unity_build/xmake.lua63
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)