Merge topic 'unity-build'

7786a05c70 Unity build: Add XCode support
1353802af3 Unity build: Add unit tests
8dfeb5d278 Unity build: Add support for Visual Studio generator
7114c141e2 Unity build: Add support for Ninja and Makefile generators

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Stanislav Ershov <digital.stream.of.mind@gmail.com>
Acked-by: Evgeniy Dushistov <dushistov@mail.ru>
Acked-by: Viktor Kirilov <vik.kirilov@gmail.com>
Merge-request: !3611
This commit is contained in:
Brad King 2019-09-05 12:35:29 +00:00 committed by Kitware Robot
commit ac4d6d4a9d
50 changed files with 665 additions and 2 deletions

View File

@ -323,6 +323,10 @@ Properties on Targets
/prop_tgt/Swift_MODULE_DIRECTORY
/prop_tgt/Swift_MODULE_NAME
/prop_tgt/TYPE
/prop_tgt/UNITY_BUILD
/prop_tgt/UNITY_BUILD_BATCH_SIZE
/prop_tgt/UNITY_BUILD_CODE_AFTER_INCLUDE
/prop_tgt/UNITY_BUILD_CODE_BEFORE_INCLUDE
/prop_tgt/VERSION
/prop_tgt/VISIBILITY_INLINES_HIDDEN
/prop_tgt/VS_CONFIGURATION_TYPE
@ -450,6 +454,7 @@ Properties on Source Files
/prop_sf/SKIP_AUTORCC
/prop_sf/SKIP_AUTOUIC
/prop_sf/SKIP_PRECOMPILE_HEADERS
/prop_sf/SKIP_UNITY_BUILD_INCLUSION
/prop_sf/Swift_DEPENDENCIES_FILE
/prop_sf/Swift_DIAGNOSTICS_FILE
/prop_sf/SYMBOLIC

View File

@ -432,6 +432,8 @@ Variables that Control the Build
/variable/CMAKE_TRY_COMPILE_CONFIGURATION
/variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
/variable/CMAKE_TRY_COMPILE_TARGET_TYPE
/variable/CMAKE_UNITY_BUILD
/variable/CMAKE_UNITY_BUILD_BATCH_SIZE
/variable/CMAKE_USE_RELATIVE_PATHS
/variable/CMAKE_VISIBILITY_INLINES_HIDDEN
/variable/CMAKE_VS_GLOBALS

View File

@ -0,0 +1,7 @@
SKIP_UNITY_BUILD_INCLUSION
--------------------------
Is this source file skipped by :prop_tgt:`UNITY_BUILD` feature.
This property helps with "ODR (One definition rule)" problems
that one would run into when using an :prop_tgt:`UNITY_BUILD`.

View File

@ -0,0 +1,55 @@
UNITY_BUILD
-----------
Should the target source files be processed into batches for
faster compilation. This feature is known as "Unity build",
or "Jumbo build".
The `C` and `CXX` source files are grouped separately.
This property is initialized by the value of the
:variable:`CMAKE_UNITY_BUILD` variable if it is set when
a target is created.
.. note ::
It's not recommended to directly set :prop_tgt:`UNITY_BUILD`
to `ON`, but to instead set :variable:`CMAKE_UNITY_BUILD` from
the command line. However, it IS recommended to set
:prop_tgt:`UNITY_BUILD` to `OFF` if you need to ensure that a
target doesn't get a unity build.
The batch size can be specified by setting
:prop_tgt:`UNITY_BUILD_BATCH_SIZE`.
The batching of source files is done by adding new sources files
wich will `#include` the source files, and exclude them from
building by setting :prop_sf:`HEADER_FILE_ONLY` to `ON`.
ODR (One definition rule) errors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Since multiple source files are included into one source file,
it can lead to ODR errors. This section contains properites
which help fixing these errors.
The source files marked by :prop_sf:`GENERATED` will be skipped
from unity build. This applies also for the source files marked
with :prop_sf:`SKIP_UNITY_BUILD_INCLUSION`.
The source files that have :prop_sf:`COMPILE_OPTIONS`,
:prop_sf:`COMPILE_DEFINITIONS`, :prop_sf:`COMPILE_FLAGS`, or
:prop_sf:`INCLUDE_DIRECTORIES` will also be skipped.
With the :prop_tgt:`UNITY_BUILD_CODE_BEFORE_INCLUDE` and
:prop_tgt:`UNITY_BUILD_CODE_AFTER_INCLUDE` one can specify code
to be injected in the unity source file before and after every
`#include` statement.
.. note ::
The order of source files defined in the `CMakeLists.txt` will
be preserved into the generated unity source files. This can
be used to manually enforce a specific grouping based on the
:prop_tgt:`UNITY_BUILD_BATCH_SIZE`.

View File

@ -0,0 +1,13 @@
UNITY_BUILD_BATCH_SIZE
----------------------
Specifies how many source code files will be included into a
:prop_tgt:`UNITY_BUILD` source file.
If the property is not set, CMake will use the value provided
by :variable:`CMAKE_UNITY_BUILD_BATCH_SIZE`.
By setting it to value `0` the generated unity source file will
contain all the source files that would be otherwise be split
into multiple batches. It is not recommended to do so, since it
would affect performance.

View File

@ -0,0 +1,8 @@
UNITY_BUILD_CODE_AFTER_INCLUDE
------------------------------
Code snippet which is included verbatim by the :prop_tgt:`UNITY_BUILD`
feature just after the `#include` statement of the targeted source
files.
This could be something like `#undef NOMINMAX`.

View File

@ -0,0 +1,8 @@
UNITY_BUILD_CODE_BEFORE_INCLUDE
-------------------------------
Code snippet which is included verbatim by the :prop_tgt:`UNITY_BUILD`
feature just before the `#include` statement of the targeted source
files.
This could be something like `#define NOMINMAX`.

View File

@ -0,0 +1,6 @@
Unity build
-----------
* The :prop_tgt:`UNITY_BUILD` target property was added to tell
generators to batch include source files for faster compilation
times.

View File

@ -0,0 +1,6 @@
CMAKE_UNITY_BUILD
-----------------
Default value for :prop_tgt:`UNITY_BUILD` of targets.
By default ``CMAKE_UNITY_BUILD`` is ``OFF``.

View File

@ -0,0 +1,6 @@
CMAKE_UNITY_BUILD_BATCH_SIZE
----------------------------
Default value for :prop_tgt:`UNITY_BUILD_BATCH_SIZE` of targets.
By default ``CMAKE_UNITY_BUILD_BATCH_SIZE`` is set to ``8``.

View File

@ -2839,6 +2839,7 @@ bool cmGlobalXCodeGenerator::CreateGroups(
continue;
}
generator->AddUnityBuild(gtgt, "");
generator->AddPchDependencies(gtgt, "");
auto addSourceToGroup = [this, mf, gtgt,

View File

@ -38,6 +38,7 @@
#include <algorithm>
#include <assert.h>
#include <cstdlib>
#include <functional>
#include <initializer_list>
#include <iterator>
@ -2199,6 +2200,101 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target,
}
}
void cmLocalGenerator::AddUnityBuild(cmGeneratorTarget* target,
const std::string& config)
{
if (!target->GetPropertyAsBool("UNITY_BUILD")) {
return;
}
const std::string buildType = cmSystemTools::UpperCase(config);
std::string filename_base =
cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/",
target->GetName(), ".dir/Unity/");
std::vector<cmSourceFile*> sources;
target->GetSourceFiles(sources, buildType);
auto batchSizeString = target->GetProperty("UNITY_BUILD_BATCH_SIZE");
const size_t unityBatchSize =
static_cast<size_t>(std::atoi(batchSizeString));
auto beforeInclude = target->GetProperty("UNITY_BUILD_CODE_BEFORE_INCLUDE");
auto afterInclude = target->GetProperty("UNITY_BUILD_CODE_AFTER_INCLUDE");
for (std::string lang : { "C", "CXX" }) {
std::vector<cmSourceFile*> filtered_sources;
std::copy_if(sources.begin(), sources.end(),
std::back_inserter(filtered_sources), [&](cmSourceFile* sf) {
return sf->GetLanguage() == lang &&
!sf->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION") &&
!sf->GetPropertyAsBool("GENERATED") &&
!sf->GetProperty("COMPILE_OPTIONS") &&
!sf->GetProperty("COMPILE_DEFINITIONS") &&
!sf->GetProperty("COMPILE_FLAGS") &&
!sf->GetProperty("INCLUDE_DIRECTORIES");
});
size_t batchSize = unityBatchSize;
if (unityBatchSize == 0) {
batchSize = filtered_sources.size();
}
for (size_t itemsLeft = filtered_sources.size(), chunk = batchSize,
batch = 0;
itemsLeft > 0; itemsLeft -= chunk, ++batch) {
chunk = std::min(itemsLeft, batchSize);
std::string filename = cmStrCat(filename_base, "unity_", batch,
(lang == "C") ? ".c" : ".cxx");
const std::string filename_tmp = cmStrCat(filename, ".tmp");
{
size_t begin = batch * batchSize;
size_t end = begin + chunk;
cmGeneratedFileStream file(
filename_tmp, false,
this->GetGlobalGenerator()->GetMakefileEncoding());
file << "/* generated by CMake */\n\n";
for (; begin != end; ++begin) {
cmSourceFile* sf = filtered_sources[begin];
// Only in Visual Studio generator we keep the source files
// for explicit processing. For the rest the source files will
// not be included in the project.
if (!this->GetGlobalGenerator()->IsMultiConfig() ||
this->GetGlobalGenerator()->IsXcode()) {
sf->SetProperty("HEADER_FILE_ONLY", "ON");
}
sf->SetProperty("UNITY_SOURCE_FILE", filename.c_str());
if (beforeInclude) {
file << beforeInclude << "\n";
}
file << "#include \"" << sf->GetFullPath() << "\"\n";
if (afterInclude) {
file << afterInclude << "\n";
}
}
}
cmSystemTools::CopyFileIfDifferent(filename_tmp, filename);
cmSystemTools::RemoveFile(filename_tmp);
target->AddSource(filename, true);
auto unity = this->Makefile->GetOrCreateSource(filename);
unity->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "ON");
unity->SetProperty("UNITY_SOURCE_FILE", filename.c_str());
}
}
}
void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags,
cmGeneratorTarget* target,
const std::string& config,

View File

@ -126,6 +126,7 @@ public:
const std::string& rawFlag) const;
void AddPchDependencies(cmGeneratorTarget* target,
const std::string& config);
void AddUnityBuild(cmGeneratorTarget* target, const std::string& config);
void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target,
const std::string& config,
const std::string& lang);

View File

@ -1321,6 +1321,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
const std::string& libName,
cmGeneratorTarget* target)
{
this->AddUnityBuild(target, "");
this->AddPchDependencies(target, "");
std::vector<std::string> configs;
@ -1509,8 +1510,11 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
const std::string& linkLanguage = gt->GetLinkerLanguage(config.c_str());
// If HEADER_FILE_ONLY is set, we must suppress this generation in
// the project file
fc.ExcludedFromBuild =
sf.GetPropertyAsBool("HEADER_FILE_ONLY") || !cmContains(acs.Configs, ci);
fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") ||
!cmContains(acs.Configs, ci) ||
(gt->GetPropertyAsBool("UNITY_BUILD") &&
sf.GetProperty("UNITY_SOURCE_FILE") &&
!sf.GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION"));
if (fc.ExcludedFromBuild) {
needfc = true;
}

View File

@ -41,6 +41,7 @@ cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
this->LocalGenerator->AddUnityBuild(target, this->ConfigName);
this->LocalGenerator->AddPchDependencies(target, this->ConfigName);
}

View File

@ -43,6 +43,7 @@ cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator(
cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
this->LocalGenerator->AddUnityBuild(target, this->ConfigName);
this->LocalGenerator->AddPchDependencies(target, this->ConfigName);
}

View File

@ -26,6 +26,7 @@ cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator(
cm::make_unique<cmOSXBundleGenerator>(target, this->ConfigName);
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
this->LocalGenerator->AddUnityBuild(target, this->ConfigName);
this->LocalGenerator->AddPchDependencies(target, this->ConfigName);
}

View File

@ -61,6 +61,7 @@ cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
cm::make_unique<cmOSXBundleGenerator>(target, this->GetConfigName());
this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
GetLocalGenerator()->AddUnityBuild(target, this->GetConfigName());
GetLocalGenerator()->AddPchDependencies(target, this->GetConfigName());
}

View File

@ -352,6 +352,8 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("Swift_MODULE_DIRECTORY");
initProp("VS_JUST_MY_CODE_DEBUGGING");
initProp("DISABLE_PRECOMPILE_HEADERS");
initProp("UNITY_BUILD");
initPropValue("UNITY_BUILD_BATCH_SIZE", "8");
#ifdef __APPLE__
if (this->GetGlobalGenerator()->IsXcode()) {
initProp("XCODE_GENERATE_SCHEME");

View File

@ -250,6 +250,7 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
this->InSourceBuild = (this->Makefile->GetCurrentSourceDirectory() ==
this->Makefile->GetCurrentBinaryDirectory());
this->LocalGenerator->AddUnityBuild(target, "");
this->LocalGenerator->AddPchDependencies(target, "");
}
@ -2070,6 +2071,17 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
if (this->GeneratorTarget->GetType() > cmStateEnums::UTILITY) {
return;
}
const bool haveUnityBuild =
this->GeneratorTarget->GetPropertyAsBool("UNITY_BUILD");
if (haveUnityBuild &&
this->GlobalGenerator->GetVersion() >=
cmGlobalVisualStudioGenerator::VS15) {
Elem e1(e0, "PropertyGroup");
e1.Element("EnableUnitySupport", "true");
}
Elem e1(e0, "ItemGroup");
e1.SetHasElements();
@ -2168,6 +2180,45 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
Elem e2(e1, tool);
this->WriteSource(e2, si.Source);
bool useNativeUnityBuild = false;
if (haveUnityBuild &&
this->GlobalGenerator->GetVersion() >=
cmGlobalVisualStudioGenerator::VS15) {
// Magic value taken from cmGlobalVisualStudioVersionedGenerator.cxx
static const std::string vs15 = "141";
std::string toolset =
this->GlobalGenerator->GetPlatformToolsetString();
cmSystemTools::ReplaceString(toolset, "v", "");
if (toolset.empty() ||
cmSystemTools::VersionCompareGreaterEq(toolset, vs15)) {
useNativeUnityBuild = true;
}
}
if (haveUnityBuild && strcmp(tool, "ClCompile") == 0 &&
si.Source->GetProperty("UNITY_SOURCE_FILE")) {
if (useNativeUnityBuild) {
e2.Attribute(
"IncludeInUnityFile",
si.Source->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION")
? "false"
: "true");
e2.Attribute("CustomUnityFile", "true");
std::string unityDir = cmSystemTools::GetFilenamePath(
si.Source->GetProperty("UNITY_SOURCE_FILE"));
e2.Attribute("UnityFilesDirectory", unityDir);
} else {
// Visual Studio versions prior to 2017 do not know about unity
// builds, thus we exclude the files alredy part of unity sources.
if (!si.Source->GetPropertyAsBool("SKIP_UNITY_BUILD_INCLUSION")) {
exclude_configs = si.Configs;
}
}
}
if (si.Kind == cmGeneratorTarget::SourceKindObjectSource) {
this->OutputSourceSpecificFlags(e2, si.Source);
}

View File

@ -576,3 +576,4 @@ endif()
add_RunCMake_test("CTestCommandExpandLists")
add_RunCMake_test(PrecompileHeaders)
add_RunCMake_test("UnityBuild")

View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.15)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1,23 @@
include(RunCMake)
run_cmake(unitybuild_c)
run_cmake(unitybuild_cxx)
run_cmake(unitybuild_c_and_cxx)
run_cmake(unitybuild_batchsize)
run_cmake(unitybuild_default_batchsize)
run_cmake(unitybuild_skip)
run_cmake(unitybuild_code_before_and_after_include)
run_cmake(unitybuild_c_no_unity_build)
run_cmake(unitybuild_order)
function(run_test name)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build)
set(RunCMake_TEST_NO_CLEAN 1)
run_cmake(${name})
run_cmake_command(${name}-build ${CMAKE_COMMAND} --build . --config Debug)
run_cmake_command(${name}-test ${CMAKE_CTEST_COMMAND} -C Debug)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_NO_CLEAN)
endfunction()
run_test(unitybuild_runtest)

View File

@ -0,0 +1,6 @@
#include "func.h"
int func(void)
{
return 0;
}

View File

@ -0,0 +1,6 @@
#ifndef func_h
#define func_h
extern int func(void);
#endif

View File

@ -0,0 +1,6 @@
#include "func.h"
int main(void)
{
return func();
}

View File

@ -0,0 +1,11 @@
set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
set(unitybuild_c1 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_1.c")
if(NOT EXISTS "${unitybuild_c0}")
set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.")
return()
endif()
if(NOT EXISTS "${unitybuild_c1}")
set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c1} does not exist.")
return()
endif()

View File

@ -0,0 +1,16 @@
project(unitybuild_batchsize C)
set(srcs "")
foreach(s RANGE 1 8)
set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
list(APPEND srcs "${src}")
endforeach()
add_library(tgt SHARED ${srcs})
set_target_properties(tgt
PROPERTIES
UNITY_BUILD ON
UNITY_BUILD_BATCH_SIZE 4
)

View File

@ -0,0 +1,5 @@
set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
if(NOT EXISTS "${unitybuild_c}")
set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} does not exist.")
return()
endif()

View File

@ -0,0 +1,12 @@
project(unitybuild_c C)
set(srcs "")
foreach(s RANGE 1 8)
set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
list(APPEND srcs "${src}")
endforeach()
add_library(tgt SHARED ${srcs})
set_target_properties(tgt PROPERTIES UNITY_BUILD ON)

View File

@ -0,0 +1,11 @@
set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
if(NOT EXISTS "${unitybuild_c}")
set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} does not exist.")
return()
endif()
set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.cxx")
if(NOT EXISTS "${unitybuild_cxx}")
set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_cxx} does not exist.")
return()
endif()

View File

@ -0,0 +1,17 @@
project(unitybuild_c_and_cxx C CXX)
set(srcs "")
foreach(s RANGE 1 8)
set(src_c "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
file(WRITE "${src_c}" "int s${s}(void) { return 0; }\n")
set(src_cxx "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx")
file(WRITE "${src_cxx}" "int s${s}(void) { return 0; }\n")
list(APPEND srcs "${src_c}")
list(APPEND srcs "${src_cxx}")
endforeach()
add_library(tgt SHARED ${srcs})
set_target_properties(tgt PROPERTIES UNITY_BUILD ON)

View File

@ -0,0 +1,5 @@
set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
if(EXISTS "${unitybuild_c}")
set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c} should not exist.")
return()
endif()

View File

@ -0,0 +1,10 @@
project(unitybuild_c_no_unity_build C)
set(srcs "")
foreach(s RANGE 1 8)
set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
list(APPEND srcs "${src}")
endforeach()
add_library(tgt SHARED ${srcs})

View File

@ -0,0 +1,7 @@
set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
file(STRINGS ${unitybuild_c} unitybuild_c_strings)
string(REGEX MATCH "#define NOMINMAX.*#include.*s1.c.*#undef NOMINMAX" matched_code ${unitybuild_c_strings})
if(NOT matched_code)
set(RunCMake_TEST_FAILED "Generated unity file doesn't include expected code before and after include")
return()
endif()

View File

@ -0,0 +1,13 @@
project(unitybuild_code_before_and_after_include C)
set(src "${CMAKE_CURRENT_BINARY_DIR}/s1.c")
file(WRITE "${src}" "int s1(void) { return 0; }\n")
add_library(tgt SHARED ${src})
set_target_properties(tgt
PROPERTIES
UNITY_BUILD ON
UNITY_BUILD_CODE_BEFORE_INCLUDE "#define NOMINMAX"
UNITY_BUILD_CODE_AFTER_INCLUDE "#undef NOMINMAX"
)

View File

@ -0,0 +1,5 @@
set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.cxx")
if(NOT EXISTS "${unitybuild_cxx}")
set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_cxx} does not exist.")
return()
endif()

View File

@ -0,0 +1,12 @@
project(unitybuild_cxx CXX)
set(srcs "")
foreach(s RANGE 1 8)
set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx")
file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
list(APPEND srcs "${src}")
endforeach()
add_library(tgt SHARED ${srcs})
set_target_properties(tgt PROPERTIES UNITY_BUILD ON)

View File

@ -0,0 +1,7 @@
set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
file(STRINGS ${unitybuild_c0} unitybuild_c_strings REGEX "/s[0-9]+.c\"$" )
list(LENGTH unitybuild_c_strings number_of_includes)
if(NOT number_of_includes EQUAL 8)
set(RunCMake_TEST_FAILED "Generated unity doesn't include the expect number of files")
return()
endif()

View File

@ -0,0 +1,15 @@
project(unitybuild_default_batchsize C)
set(srcs "")
foreach(s RANGE 1 10)
set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
list(APPEND srcs "${src}")
endforeach()
add_library(tgt SHARED ${srcs})
set_target_properties(tgt
PROPERTIES
UNITY_BUILD ON
)

View File

@ -0,0 +1,7 @@
set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
file(STRINGS ${unitybuild_c} unitybuild_c_strings)
string(REGEX MATCH ".*#include.*s3.c.*#include.*s1.c.*#include.*s2.c.*" matched_code ${unitybuild_c_strings})
if(NOT matched_code)
set(RunCMake_TEST_FAILED "Generated unity file doesn't include expected oder of source files")
return()
endif()

View File

@ -0,0 +1,12 @@
project(unitybuild_order C)
set(srcs "")
foreach(s 3 1 2)
set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
list(APPEND srcs "${src}")
endforeach()
add_library(tgt SHARED ${srcs})
set_target_properties(tgt PROPERTIES UNITY_BUILD ON)

View File

@ -0,0 +1,8 @@
project(unitybuild_runtest C)
set(CMAKE_UNITY_BUILD ON) # This tests that the variable works in addition to the property
add_executable(main main.c func.c)
enable_testing()
add_test(NAME main COMMAND main)

View File

@ -0,0 +1,14 @@
set(unitybuild_c "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
file(STRINGS ${unitybuild_c} unitybuild_c_strings)
string(REGEX MATCH "\\/s[1-6].c" matched_files_1_6 ${unitybuild_c_strings})
if(matched_files_1_6)
set(RunCMake_TEST_FAILED "Generated unity contains s1.c -> s6.c which should have been skipped")
return()
endif()
string(REGEX MATCH "\\/s[7-8].c" matched_files_7_8 ${unitybuild_c_strings})
if(NOT matched_files_7_8)
set(RunCMake_TEST_FAILED "Generated unity should have contained s7.c, s8.c!")
return()
endif()

View File

@ -0,0 +1,30 @@
project(unitybuild_skip C)
set(srcs "")
foreach(s RANGE 1 8)
set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
list(APPEND srcs "${src}")
endforeach()
add_library(tgt SHARED ${srcs})
set_target_properties(tgt PROPERTIES UNITY_BUILD ON)
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s1.c
PROPERTIES GENERATED ON)
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s2.c
PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s3.c
PROPERTIES COMPILE_OPTIONS "val")
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s4.c
PROPERTIES COMPILE_DEFINITIONS "val")
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s5.c
PROPERTIES COMPILE_FLAGS "val")
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/s6.c
PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}")

View File

@ -34,3 +34,12 @@ endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.20)
run_cmake(VsSpectreMitigation)
endif()
# Visual Studio 2017 has toolset version 141
string(REPLACE "v" "" generator_toolset "${RunCMake_GENERATOR_TOOLSET}")
if (RunCMake_GENERATOR MATCHES "Visual Studio 1[0-4] 201[0-5]" OR
(RunCMake_GENERATOR_TOOLSET AND generator_toolset VERSION_LESS "141"))
run_cmake(UnityBuildPre2017)
else()
run_cmake(UnityBuildNative)
endif()

View File

@ -0,0 +1,45 @@
set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
if(NOT EXISTS "${unitybuild_c0}")
set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.")
return()
endif()
set(tgt_project "${RunCMake_TEST_BINARY_DIR}/tgt.vcxproj")
if (NOT EXISTS "${tgt_project}")
set(RunCMake_TEST_FAILED "Generated project file ${tgt_project} doesn't exist.")
return()
endif()
file(STRINGS ${tgt_project} tgt_projects_strings)
foreach(line IN LISTS tgt_projects_strings)
if (line MATCHES "<EnableUnitySupport>true</EnableUnitySupport>")
set(have_unity_support ON)
endif()
if (line MATCHES "<ClCompile Include=.*IncludeInUnityFile=\"false\" CustomUnityFile=\"true\"")
set(unity_source_line ${line})
endif()
if (line MATCHES "<ClCompile Include=.*IncludeInUnityFile=\"true\" CustomUnityFile=\"true\"")
list(APPEND sources_list ${line})
endif()
endforeach()
if (NOT have_unity_support)
set(RunCMake_TEST_FAILED "Generated project should include the <EnableUnitySupport> block.")
return()
endif()
string(REPLACE "\\" "/" unity_source_line "${unity_source_line}")
string(FIND "${unity_source_line}" "CMakeFiles/tgt.dir/Unity/unity_0.c" unity_source_file_position)
if (unity_source_file_position EQUAL "-1")
set(RunCMake_TEST_FAILED "Generated project should include the generated unity source file.")
return()
endif()
list(LENGTH sources_list number_of_sources)
if(NOT number_of_sources EQUAL 8)
set(RunCMake_TEST_FAILED "Generated project doesn't include the expect number of files.")
return()
endif()

View File

@ -0,0 +1,12 @@
project(unitybuild_c C)
set(srcs "")
foreach(s RANGE 1 8)
set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
list(APPEND srcs "${src}")
endforeach()
add_library(tgt SHARED ${srcs})
set_target_properties(tgt PROPERTIES UNITY_BUILD ON)

View File

@ -0,0 +1,48 @@
set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/tgt.dir/Unity/unity_0.c")
if(NOT EXISTS "${unitybuild_c0}")
set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.")
return()
endif()
set(tgt_project "${RunCMake_TEST_BINARY_DIR}/tgt.vcxproj")
if (NOT EXISTS "${tgt_project}")
set(RunCMake_TEST_FAILED "Generated project file ${tgt_project} doesn't exist.")
return()
endif()
file(STRINGS ${tgt_project} tgt_projects_strings)
foreach(line IN LISTS tgt_projects_strings)
if (line MATCHES "<ClCompile Include=.*/>")
set(unity_source_line ${line})
endif()
if (line MATCHES "<ClCompile Include=\"[^\"]*\">")
string(REGEX MATCH "<ClCompile Include=\"([^\"]*)\">" source_file ${line})
list(APPEND sources_list ${source_file})
endif()
if (line MATCHES "<ExcludedFromBuild.*</ExcludedFromBuild>")
list(APPEND excluded_sources_list ${source_file})
endif()
endforeach()
string(REPLACE "\\" "/" unity_source_line ${unity_source_line})
string(FIND "${unity_source_line}" "CMakeFiles/tgt.dir/Unity/unity_0.c" unity_source_file_position)
if (unity_source_file_position EQUAL "-1")
set(RunCMake_TEST_FAILED "Generated project should include the generated unity source file.")
return()
endif()
list(LENGTH sources_list number_of_sources)
if(NOT number_of_sources EQUAL 8)
set(RunCMake_TEST_FAILED "Generated project doesn't include the expect number of files.")
return()
endif()
# Exclusions for Debug|Release|MinSizeRel|RelWithDebInfo
list(LENGTH excluded_sources_list number_of_excluded_sources)
if(NOT number_of_excluded_sources EQUAL 32)
set(RunCMake_TEST_FAILED "Generated project doesn't exclude the source files for all configurations.")
return()
endif()

View File

@ -0,0 +1,12 @@
project(unitybuild_c C)
set(srcs "")
foreach(s RANGE 1 8)
set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
list(APPEND srcs "${src}")
endforeach()
add_library(tgt SHARED ${srcs})
set_target_properties(tgt PROPERTIES UNITY_BUILD ON)