summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt11
-rw-r--r--Help/command/FIND_XXX.txt5
-rw-r--r--Help/command/find_package.rst5
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst4
-rw-r--r--Help/release/dev/cpackifw-search-algorithm.rst7
-rw-r--r--Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst8
-rw-r--r--Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst5
-rw-r--r--Modules/CPackIFW.cmake53
-rw-r--r--Modules/FindMPI.cmake1
-rw-r--r--Modules/InstallRequiredSystemLibraries.cmake6
-rw-r--r--Modules/Platform/Linux-TinyCC-C.cmake1
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/QtDialog/CMakeLists.txt2
-rw-r--r--Source/QtDialog/cmake-gui.desktop (renamed from Source/QtDialog/CMake.desktop)0
-rw-r--r--Source/cmExportBuildFileGenerator.cxx4
-rw-r--r--Source/cmFileCommand.cxx61
-rw-r--r--Source/cmGeneratorTarget.cxx74
-rw-r--r--Source/cmGeneratorTarget.h20
-rw-r--r--Source/cmGlobalVisualStudio14Generator.cxx46
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx47
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx84
-rw-r--r--Source/cmLocalVisualStudio7Generator.h3
-rw-r--r--Source/cmTarget.cxx11
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx66
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h1
-rw-r--r--Tests/RunCMake/CMP0026/CMP0026-OLD.cmake12
-rw-r--r--Tests/RunCMake/CMP0026/RunCMakeTest.cmake1
-rw-r--r--Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad-result.txt1
-rw-r--r--Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad-stderr.txt15
-rw-r--r--Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad.cmake5
-rw-r--r--Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-stdout.txt8
-rw-r--r--Tests/RunCMake/file/INSTALL-FILES_FROM_DIR.cmake7
-rw-r--r--Tests/RunCMake/file/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/file/from/a.txt0
-rw-r--r--Tests/RunCMake/file/from/a/b.txt0
-rw-r--r--Tests/RunCMake/file/from/a/b/c.txt0
-rw-r--r--Utilities/IWYU/mapping.imp136
38 files changed, 589 insertions, 126 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ed5de10..545177b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -226,6 +226,17 @@ option(CMAKE_USE_FOLDERS "Enable folder grouping of projects in IDEs." ON)
mark_as_advanced(CMAKE_USE_FOLDERS)
+option(CMake_RUN_IWYU "Run include-what-you-use with the compiler." OFF)
+if(CMake_RUN_IWYU)
+ find_program(IWYU_COMMAND NAMES include-what-you-use iwyu)
+ if(NOT IWYU_COMMAND)
+ message(FATAL_ERROR "CMake_RUN_IWYU is ON but include-what-you-use is not found!")
+ endif()
+ set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE
+ "${IWYU_COMMAND};-Xiwyu;--mapping_file=${CMake_SOURCE_DIR}/Utilities/IWYU/mapping.imp")
+endif()
+
+
#-----------------------------------------------------------------------
# a macro that only sets the FOLDER target property if it's
# "appropriate"
diff --git a/Help/command/FIND_XXX.txt b/Help/command/FIND_XXX.txt
index bd4d295..2f27764 100644
--- a/Help/command/FIND_XXX.txt
+++ b/Help/command/FIND_XXX.txt
@@ -73,6 +73,7 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
1. Search paths specified in cmake-specific cache variables.
These are intended to be used on the command line with a ``-DVAR=value``.
+ The values are interpreted as :ref:`;-lists <CMake Language Lists>`.
This can be skipped if ``NO_CMAKE_PATH`` is passed.
* |CMAKE_PREFIX_PATH_XXX|
@@ -80,7 +81,9 @@ If ``NO_DEFAULT_PATH`` is not specified, the search process is as follows:
* |CMAKE_XXX_MAC_PATH|
2. Search paths specified in cmake-specific environment variables.
- These are intended to be set in the user's shell configuration.
+ These are intended to be set in the user's shell configuration,
+ and therefore use the host's native path separator
+ (``;`` on Windows and ``:`` on UNIX).
This can be skipped if ``NO_CMAKE_ENVIRONMENT_PATH`` is passed.
* |CMAKE_PREFIX_PATH_XXX|
diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
index 2cb1e5f..60a77b8 100644
--- a/Help/command/find_package.rst
+++ b/Help/command/find_package.rst
@@ -251,6 +251,7 @@ enabled.
1. Search paths specified in cmake-specific cache variables. These
are intended to be used on the command line with a ``-DVAR=value``.
+ The values are interpreted as :ref:`;-lists <CMake Language Lists>`.
This can be skipped if ``NO_CMAKE_PATH`` is passed::
CMAKE_PREFIX_PATH
@@ -258,7 +259,9 @@ enabled.
CMAKE_APPBUNDLE_PATH
2. Search paths specified in cmake-specific environment variables.
- These are intended to be set in the user's shell configuration.
+ These are intended to be set in the user's shell configuration,
+ and therefore use the host's native path separator
+ (``;`` on Windows and ``:`` on UNIX).
This can be skipped if ``NO_CMAKE_ENVIRONMENT_PATH`` is passed::
<package>_DIR
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 0a68815..7347bcc 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -292,6 +292,7 @@ Variables that Control the Build
/variable/CMAKE_INSTALL_RPATH
/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH
/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION
+ /variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG
/variable/CMAKE_IOS_INSTALL_COMBINED
/variable/CMAKE_LANG_CLANG_TIDY
/variable/CMAKE_LANG_COMPILER_LAUNCHER
diff --git a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
index 492fee0..782b0f0 100644
--- a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
+++ b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
@@ -6,3 +6,7 @@ Per-configuration interprocedural optimization for a target.
This is a per-configuration version of INTERPROCEDURAL_OPTIMIZATION.
If set, this property overrides the generic property for the named
configuration.
+
+This property is initialized by the
+:variable:`CMAKE_INTERPROCEDURAL_OPTIMIZATION_<CONFIG>` variable if it is set
+when a target is created.
diff --git a/Help/release/dev/cpackifw-search-algorithm.rst b/Help/release/dev/cpackifw-search-algorithm.rst
new file mode 100644
index 0000000..f2e9985
--- /dev/null
+++ b/Help/release/dev/cpackifw-search-algorithm.rst
@@ -0,0 +1,7 @@
+cpackifw-search-algorithm
+-------------------------
+
+* The :module:`CPackIFW` module learned the new hint :variable:`CPACK_IFW_ROOT`
+ variable for finding the QtIFW tool suite installed in a non-standard place.
+* The :module:`CPackIFW` module tries to find and use QtIFW tools of the `3.0`
+ and `3.1` versions.
diff --git a/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst b/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
new file mode 100644
index 0000000..b291102
--- /dev/null
+++ b/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst
@@ -0,0 +1,8 @@
+CMAKE_INTERPROCEDURAL_OPTIMIZATION_<CONFIG>
+-------------------------------------------
+
+Default value for :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION_<CONFIG>` of targets.
+
+This variable is used to initialize the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION_<CONFIG>`
+property on all the targets. See that target property for additional
+information.
diff --git a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst
index e0be3a4..83b9bc1 100644
--- a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst
+++ b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION.rst
@@ -10,3 +10,8 @@ version. Otherwise CMake computes a default version based on the Windows
SDK versions available. The chosen Windows target version number is provided
in ``CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION``. If no Windows 10 SDK
is available this value will be empty.
+
+One may set a ``CMAKE_WINDOWS_KITS_10_DIR`` *environment variable*
+to an absolute path to tell CMake to look for Windows 10 SDKs in
+a custom location. The specified directory is expected to contain
+``Include/10.0.*`` directories.
diff --git a/Modules/CPackIFW.cmake b/Modules/CPackIFW.cmake
index deb724c..099dd1c 100644
--- a/Modules/CPackIFW.cmake
+++ b/Modules/CPackIFW.cmake
@@ -28,8 +28,32 @@
# and Mac OS X.
#
# You should also install QtIFW_ to use CPack ``IFW`` generator.
-# If you don't use a default path for the installation, please set
-# the used path in the variable ``QTIFWDIR``.
+#
+# Hints
+# ^^^^^
+#
+# Generally, the CPack ``IFW`` generator automatically finds QtIFW_ tools,
+# but if you don't use a default path for installation of the QtIFW_ tools,
+# the path may be specified in either a CMake or an environment variable:
+#
+# .. variable:: CPACK_IFW_ROOT
+#
+# An CMake variable which specifies the location of the QtIFW_ tool suite.
+#
+# The variable will be cached in the ``CPackConfig.cmake`` file and used at
+# CPack runtime.
+#
+# .. variable:: QTIFWDIR
+#
+# An environment variable which specifies the location of the QtIFW_ tool
+# suite.
+#
+# .. note::
+# The specified path should not contain "bin" at the end
+# (for example: "D:\\DevTools\\QtIFW2.0.5").
+#
+# The :variable:`CPACK_IFW_ROOT` variable has a higher priority and overrides
+# the value of the :variable:`QTIFWDIR` variable.
#
# Variables
# ^^^^^^^^^
@@ -197,7 +221,7 @@
# dependent components.
#
# Tools
-# """"""""
+# """""
#
# .. variable:: CPACK_IFW_FRAMEWORK_VERSION
#
@@ -207,13 +231,25 @@
#
# The path to "binarycreator" command line client.
#
-# This variable is cached and can be configured user if need.
+# This variable is cached and may be configured if needed.
#
# .. variable:: CPACK_IFW_REPOGEN_EXECUTABLE
#
# The path to "repogen" command line client.
#
-# This variable is cached and can be configured user if need.
+# This variable is cached and may be configured if needed.
+#
+# .. variable:: CPACK_IFW_INSTALLERBASE_EXECUTABLE
+#
+# The path to "installerbase" installer executable base.
+#
+# This variable is cached and may be configured if needed.
+#
+# .. variable:: CPACK_IFW_DEVTOOL_EXECUTABLE
+#
+# The path to "devtool" command line client.
+#
+# This variable is cached and may be configured if needed.
#
# Commands
# ^^^^^^^^^
@@ -568,7 +604,7 @@
# Default path
-foreach(_CPACK_IFW_PATH_VAR "QTIFWDIR" "QTDIR")
+foreach(_CPACK_IFW_PATH_VAR "CPACK_IFW_ROOT" "QTIFWDIR" "QTDIR")
if(DEFINED ${_CPACK_IFW_PATH_VAR}
AND NOT "${${_CPACK_IFW_PATH_VAR}}" STREQUAL "")
list(APPEND _CPACK_IFW_PATHS "${${_CPACK_IFW_PATH_VAR}}")
@@ -597,6 +633,10 @@ set(_CPACK_IFW_PREFIXES
"QtIFW-")
set(_CPACK_IFW_VERSIONS
+ "3.1"
+ "3.1.0"
+ "3.0"
+ "3.0.0"
"2.3"
"2.3.0"
"2.2"
@@ -604,6 +644,7 @@ set(_CPACK_IFW_VERSIONS
"2.1"
"2.1.0"
"2.0"
+ "2.0.5"
"2.0.3"
"2.0.2"
"2.0.1"
diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake
index 32164a1..3e8be5b 100644
--- a/Modules/FindMPI.cmake
+++ b/Modules/FindMPI.cmake
@@ -689,6 +689,7 @@ if (MPI_NUMLIBS GREATER 1)
else()
set(MPI_EXTRA_LIBRARY "MPI_EXTRA_LIBRARY-NOTFOUND" CACHE STRING "Extra MPI libraries to link against" FORCE)
endif()
+mark_as_advanced(MPI_LIBRARY MPI_EXTRA_LIBRARY)
#=============================================================================
# unset these vars to cleanup namespace
diff --git a/Modules/InstallRequiredSystemLibraries.cmake b/Modules/InstallRequiredSystemLibraries.cmake
index a3478a3..6d33fc6 100644
--- a/Modules/InstallRequiredSystemLibraries.cmake
+++ b/Modules/InstallRequiredSystemLibraries.cmake
@@ -31,6 +31,11 @@
# app-local deployment (e.g. to Windows XP). This is meaningful
# only with MSVC from Visual Studio 2015 or higher.
#
+# One may set a ``CMAKE_WINDOWS_KITS_10_DIR`` *environment variable*
+# to an absolute path to tell CMake to look for Windows 10 SDKs in
+# a custom location. The specified directory is expected to contain
+# ``Redist/ucrt/DLLs/*`` directories.
+#
# ``CMAKE_INSTALL_MFC_LIBRARIES``
# Set to TRUE to install the MSVC MFC runtime libraries.
#
@@ -258,6 +263,7 @@ if(MSVC)
set(programfilesx86 "ProgramFiles(x86)")
find_path(WINDOWS_KITS_DIR NAMES Redist/ucrt/DLLs/${CMAKE_MSVC_ARCH}/ucrtbase.dll
PATHS
+ $ENV{CMAKE_WINDOWS_KITS_10_DIR}
"${windows_kits_dir}"
"$ENV{ProgramFiles}/Windows Kits/10"
"$ENV{${programfilesx86}}/Windows Kits/10"
diff --git a/Modules/Platform/Linux-TinyCC-C.cmake b/Modules/Platform/Linux-TinyCC-C.cmake
index f78e708..9409d8b 100644
--- a/Modules/Platform/Linux-TinyCC-C.cmake
+++ b/Modules/Platform/Linux-TinyCC-C.cmake
@@ -2,3 +2,4 @@ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "")
set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP "")
set(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "")
set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-soname ")
+set(CMAKE_EXE_EXPORTS_C_FLAG "-rdynamic ")
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index ac8f2df..9219dae 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 8)
-set(CMake_VERSION_PATCH 20170414)
+set(CMake_VERSION_PATCH 20170419)
#set(CMake_VERSION_RC 1)
diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt
index 10fd718..2e11a8a 100644
--- a/Source/QtDialog/CMakeLists.txt
+++ b/Source/QtDialog/CMakeLists.txt
@@ -198,7 +198,7 @@ if(UNIX AND NOT APPLE)
# install a desktop file so CMake appears in the application start menu
# with an icon
- install(FILES CMake.desktop
+ install(FILES cmake-gui.desktop
DESTINATION "${CMAKE_XDGDATA_DIR}/applications"
${COMPONENT})
install(FILES cmakecache.xml
diff --git a/Source/QtDialog/CMake.desktop b/Source/QtDialog/cmake-gui.desktop
index 842091f..842091f 100644
--- a/Source/QtDialog/CMake.desktop
+++ b/Source/QtDialog/cmake-gui.desktop
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index 0c25268..539d854 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -185,9 +185,7 @@ void cmExportBuildFileGenerator::SetImportLocationProperty(
}
// Add the import library for windows DLLs.
- if (target->IsDLLPlatform() &&
- (target->GetType() == cmStateEnums::SHARED_LIBRARY ||
- target->IsExecutableWithExports()) &&
+ if (target->HasImportLibrary() &&
mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
std::string prop = "IMPORTED_IMPLIB";
prop += suffix;
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index deb7187..034a266 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -1147,6 +1147,7 @@ protected:
bool UseGivenPermissionsDir;
bool UseSourcePermissions;
std::string Destination;
+ std::string FilesFromDir;
std::vector<std::string> Files;
int Doing;
@@ -1156,6 +1157,7 @@ protected:
DoingNone,
DoingError,
DoingDestination,
+ DoingFilesFromDir,
DoingFiles,
DoingPattern,
DoingRegex,
@@ -1251,6 +1253,12 @@ bool cmFileCopier::CheckKeyword(std::string const& arg)
} else {
this->Doing = DoingDestination;
}
+ } else if (arg == "FILES_FROM_DIR") {
+ if (this->CurrentMatchRule) {
+ this->NotAfterMatch(arg);
+ } else {
+ this->Doing = DoingFilesFromDir;
+ }
} else if (arg == "PATTERN") {
this->Doing = DoingPattern;
} else if (arg == "REGEX") {
@@ -1314,13 +1322,7 @@ bool cmFileCopier::CheckValue(std::string const& arg)
{
switch (this->Doing) {
case DoingFiles:
- if (arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str())) {
- this->Files.push_back(arg);
- } else {
- std::string file = this->Makefile->GetCurrentSourceDirectory();
- file += "/" + arg;
- this->Files.push_back(file);
- }
+ this->Files.push_back(arg);
break;
case DoingDestination:
if (arg.empty() || cmSystemTools::FileIsFullPath(arg.c_str())) {
@@ -1331,6 +1333,16 @@ bool cmFileCopier::CheckValue(std::string const& arg)
}
this->Doing = DoingNone;
break;
+ case DoingFilesFromDir:
+ if (cmSystemTools::FileIsFullPath(arg.c_str())) {
+ this->FilesFromDir = arg;
+ } else {
+ this->FilesFromDir = this->Makefile->GetCurrentSourceDirectory();
+ this->FilesFromDir += "/" + arg;
+ }
+ cmSystemTools::ConvertToUnixSlashes(this->FilesFromDir);
+ this->Doing = DoingNone;
+ break;
case DoingPattern: {
// Convert the pattern to a regular expression. Require a
// leading slash and trailing end-of-string in the matched
@@ -1390,17 +1402,41 @@ bool cmFileCopier::Run(std::vector<std::string> const& args)
return false;
}
- std::vector<std::string> const& files = this->Files;
- for (std::vector<std::string>::size_type i = 0; i < files.size(); ++i) {
+ for (std::vector<std::string>::const_iterator i = this->Files.begin();
+ i != this->Files.end(); ++i) {
+ std::string file;
+ if (!i->empty() && !cmSystemTools::FileIsFullPath(*i)) {
+ if (!this->FilesFromDir.empty()) {
+ file = this->FilesFromDir;
+ } else {
+ file = this->Makefile->GetCurrentSourceDirectory();
+ }
+ file += "/";
+ file += *i;
+ } else if (!this->FilesFromDir.empty()) {
+ this->FileCommand->SetError("option FILES_FROM_DIR requires all files "
+ "to be specified as relative paths.");
+ return false;
+ } else {
+ file = *i;
+ }
+
// Split the input file into its directory and name components.
std::vector<std::string> fromPathComponents;
- cmSystemTools::SplitPath(files[i], fromPathComponents);
+ cmSystemTools::SplitPath(file, fromPathComponents);
std::string fromName = *(fromPathComponents.end() - 1);
std::string fromDir = cmSystemTools::JoinPath(
fromPathComponents.begin(), fromPathComponents.end() - 1);
// Compute the full path to the destination file.
std::string toFile = this->Destination;
+ if (!this->FilesFromDir.empty()) {
+ std::string dir = cmSystemTools::GetFilenamePath(*i);
+ if (!dir.empty()) {
+ toFile += "/";
+ toFile += dir;
+ }
+ }
std::string const& toName = this->ToName(fromName);
if (!toName.empty()) {
toFile += "/";
@@ -1751,6 +1787,11 @@ bool cmFileInstaller::Parse(std::vector<std::string> const& args)
}
if (!this->Rename.empty()) {
+ if (!this->FilesFromDir.empty()) {
+ this->FileCommand->SetError("INSTALL option RENAME may not be "
+ "combined with FILES_FROM_DIR.");
+ return false;
+ }
if (this->InstallType != cmInstallType_FILES &&
this->InstallType != cmInstallType_PROGRAMS) {
this->FileCommand->SetError("INSTALL option RENAME may be used "
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 5e4259d..32e2b00 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -941,6 +941,26 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<std::string>& files,
void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
const std::string& config) const
{
+ if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ // Since we are still configuring not all sources may exist yet,
+ // so we need to avoid full source classification because that
+ // requires the absolute paths to all sources to be determined.
+ // Since this is only for compatibility with old policies that
+ // projects should not depend on anymore, just compute the files
+ // without memoizing them.
+ std::vector<std::string> srcs;
+ this->GetSourceFiles(srcs, config);
+ std::set<cmSourceFile*> emitted;
+ for (std::vector<std::string>::const_iterator i = srcs.begin();
+ i != srcs.end(); ++i) {
+ cmSourceFile* sf = this->Makefile->GetOrCreateSource(*i);
+ if (emitted.insert(sf).second) {
+ files.push_back(sf);
+ }
+ }
+ return;
+ }
+
KindedSources const& kinded = this->GetKindedSources(config);
files.reserve(kinded.Sources.size());
for (std::vector<SourceAndKind>::const_iterator si = kinded.Sources.begin();
@@ -949,6 +969,19 @@ void cmGeneratorTarget::GetSourceFiles(std::vector<cmSourceFile*>& files,
}
}
+void cmGeneratorTarget::GetSourceFilesWithoutObjectLibraries(
+ std::vector<cmSourceFile*>& files, const std::string& config) const
+{
+ KindedSources const& kinded = this->GetKindedSources(config);
+ files.reserve(kinded.Sources.size());
+ for (std::vector<SourceAndKind>::const_iterator si = kinded.Sources.begin();
+ si != kinded.Sources.end(); ++si) {
+ if (si->Source->GetObjectLibrary().empty()) {
+ files.push_back(si->Source);
+ }
+ }
+}
+
cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources(
std::string const& config) const
{
@@ -1069,6 +1102,43 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
}
}
+std::vector<cmGeneratorTarget::AllConfigSource> const&
+cmGeneratorTarget::GetAllConfigSources() const
+{
+ if (this->AllConfigSources.empty()) {
+ this->ComputeAllConfigSources();
+ }
+ return this->AllConfigSources;
+}
+
+void cmGeneratorTarget::ComputeAllConfigSources() const
+{
+ std::vector<std::string> configs;
+ this->Makefile->GetConfigurations(configs);
+
+ std::map<cmSourceFile const*, size_t> index;
+
+ for (size_t ci = 0; ci < configs.size(); ++ci) {
+ KindedSources const& sources = this->GetKindedSources(configs[ci]);
+ for (std::vector<cmGeneratorTarget::SourceAndKind>::const_iterator si =
+ sources.Sources.begin();
+ si != sources.Sources.end(); ++si) {
+ std::map<cmSourceFile const*, size_t>::iterator mi =
+ index.find(si->Source);
+ if (mi == index.end()) {
+ AllConfigSource acs;
+ acs.Source = si->Source;
+ acs.Kind = si->Kind;
+ this->AllConfigSources.push_back(acs);
+ std::map<cmSourceFile const*, size_t>::value_type entry(
+ si->Source, this->AllConfigSources.size() - 1);
+ mi = index.insert(entry).first;
+ }
+ this->AllConfigSources[mi->second].Configs.push_back(ci);
+ }
+ }
+}
+
std::string cmGeneratorTarget::GetCompilePDBName(
const std::string& config) const
{
@@ -4900,11 +4970,11 @@ bool cmGeneratorTarget::GetConfigCommonSourceFiles(
std::vector<std::string>::const_iterator it = configs.begin();
const std::string& firstConfig = *it;
- this->GetSourceFiles(files, firstConfig);
+ this->GetSourceFilesWithoutObjectLibraries(files, firstConfig);
for (; it != configs.end(); ++it) {
std::vector<cmSourceFile*> configFiles;
- this->GetSourceFiles(configFiles, *it);
+ this->GetSourceFilesWithoutObjectLibraries(configFiles, *it);
if (configFiles != files) {
std::string firstConfigFiles;
const char* sep = "";
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 7c86d30..d4f48fe 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -12,6 +12,7 @@
#include <map>
#include <set>
+#include <stddef.h>
#include <string>
#include <utility>
#include <vector>
@@ -69,6 +70,8 @@ public:
bool GetPropertyAsBool(const std::string& prop) const;
void GetSourceFiles(std::vector<cmSourceFile*>& files,
const std::string& config) const;
+ void GetSourceFilesWithoutObjectLibraries(std::vector<cmSourceFile*>& files,
+ const std::string& config) const;
/** Source file kinds (classifications).
Generators use this to decide how to treat a source file. */
@@ -107,6 +110,17 @@ public:
/** Get all sources needed for a configuration with kinds assigned. */
KindedSources const& GetKindedSources(std::string const& config) const;
+ struct AllConfigSource
+ {
+ cmSourceFile const* Source;
+ cmGeneratorTarget::SourceKind Kind;
+ std::vector<size_t> Configs;
+ };
+
+ /** Get all sources needed for all configurations with kinds and
+ per-source configurations assigned. */
+ std::vector<AllConfigSource> const& GetAllConfigSources() const;
+
void GetObjectSources(std::vector<cmSourceFile const*>&,
const std::string& config) const;
const std::string& GetObjectName(cmSourceFile const* file);
@@ -338,6 +352,9 @@ public:
std::string GetFullNameImported(const std::string& config,
bool implib) const;
+ /** Get source files common to all configurations and diagnose cases
+ with per-config sources. Excludes sources added by a TARGET_OBJECTS
+ generator expression. */
bool GetConfigCommonSourceFiles(std::vector<cmSourceFile*>& files) const;
bool HaveBuildTreeRPATH(const std::string& config) const;
@@ -731,6 +748,9 @@ private:
void ComputeKindedSources(KindedSources& files,
std::string const& config) const;
+ mutable std::vector<AllConfigSource> AllConfigSources;
+ void ComputeAllConfigSources() const;
+
std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
std::vector<TargetPropertyEntry*> CompileOptionsEntries;
std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index d2ac36b..df086d3 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -217,24 +217,44 @@ struct NoWindowsH
std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion()
{
#if defined(_WIN32) && !defined(__CYGWIN__)
- // This logic is taken from the vcvarsqueryregistry.bat file from VS2015
- // Try HKLM and then HKCU.
- std::string win10Root;
- if (!cmSystemTools::ReadRegistryValue(
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
- "Windows Kits\\Installed Roots;KitsRoot10",
- win10Root, cmSystemTools::KeyWOW64_32) &&
- !cmSystemTools::ReadRegistryValue(
- "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\"
- "Windows Kits\\Installed Roots;KitsRoot10",
- win10Root, cmSystemTools::KeyWOW64_32)) {
+ std::vector<std::string> win10Roots;
+
+ {
+ std::string win10Root;
+ if (cmSystemTools::GetEnv("CMAKE_WINDOWS_KITS_10_DIR", win10Root)) {
+ cmSystemTools::ConvertToUnixSlashes(win10Root);
+ win10Roots.push_back(win10Root);
+ }
+ }
+
+ {
+ // This logic is taken from the vcvarsqueryregistry.bat file from VS2015
+ // Try HKLM and then HKCU.
+ std::string win10Root;
+ if (cmSystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\"
+ "Windows Kits\\Installed Roots;KitsRoot10",
+ win10Root, cmSystemTools::KeyWOW64_32) ||
+ cmSystemTools::ReadRegistryValue(
+ "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\"
+ "Windows Kits\\Installed Roots;KitsRoot10",
+ win10Root, cmSystemTools::KeyWOW64_32)) {
+ cmSystemTools::ConvertToUnixSlashes(win10Root);
+ win10Roots.push_back(win10Root);
+ }
+ }
+
+ if (win10Roots.empty()) {
return std::string();
}
std::vector<std::string> sdks;
- std::string path = win10Root + "Include/*";
// Grab the paths of the different SDKs that are installed
- cmSystemTools::GlobDirs(path, sdks);
+ for (std::vector<std::string>::iterator i = win10Roots.begin();
+ i != win10Roots.end(); ++i) {
+ std::string path = *i + "/Include/*";
+ cmSystemTools::GlobDirs(path, sdks);
+ }
// Skip SDKs that do not contain <um/windows.h> because that indicates that
// only the UCRT MSIs were installed for them.
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 10343fd..ecc3e31 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -651,11 +651,6 @@ std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target,
return key;
}
-std::string GetGroupMapKey(cmGeneratorTarget* target, cmSourceFile* sf)
-{
- return GetGroupMapKeyFromPath(target, sf->GetFullPath());
-}
-
cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath(
const std::string& fullpath, cmGeneratorTarget* target,
const std::string& lang, cmSourceFile* sf)
@@ -2673,7 +2668,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target)
std::string linkObjs;
const char* sep = "";
std::vector<cmSourceFile const*> objs;
- gt->GetExternalObjects(objs, "");
+ gt->GetExternalObjects(objs, configName);
for (std::vector<cmSourceFile const*>::const_iterator oi = objs.begin();
oi != objs.end(); ++oi) {
if ((*oi)->GetObjectLibrary().empty()) {
@@ -2788,42 +2783,26 @@ bool cmGlobalXCodeGenerator::CreateGroups(
gtgt->AddSource(plist);
}
- std::vector<cmSourceFile*> classes;
- if (!gtgt->GetConfigCommonSourceFiles(classes)) {
- return false;
- }
+ std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
+ gtgt->GetAllConfigSources();
+
// Put cmSourceFile instances in proper groups:
- for (std::vector<cmSourceFile*>::const_iterator s = classes.begin();
- s != classes.end(); s++) {
- cmSourceFile* sf = *s;
+ for (std::vector<cmGeneratorTarget::AllConfigSource>::const_iterator si =
+ sources.begin();
+ si != sources.end(); ++si) {
+ cmSourceFile const* sf = si->Source;
+ if (this->XcodeVersion >= 50 && !sf->GetObjectLibrary().empty()) {
+ // Object library files go on the link line instead.
+ continue;
+ }
// Add the file to the list of sources.
std::string const& source = sf->GetFullPath();
cmSourceGroup* sourceGroup =
mf->FindSourceGroup(source.c_str(), sourceGroups);
cmXCodeObject* pbxgroup = this->CreateOrGetPBXGroup(gtgt, sourceGroup);
- std::string key = GetGroupMapKey(gtgt, sf);
+ std::string key = GetGroupMapKeyFromPath(gtgt, source);
this->GroupMap[key] = pbxgroup;
}
-
- if (this->XcodeVersion < 50) {
- // Put OBJECT_LIBRARY objects in proper groups:
- std::vector<cmSourceFile const*> objs;
- gtgt->GetExternalObjects(objs, "");
- for (std::vector<cmSourceFile const*>::const_iterator oi =
- objs.begin();
- oi != objs.end(); ++oi) {
- if ((*oi)->GetObjectLibrary().empty()) {
- continue;
- }
- std::string const& source = (*oi)->GetFullPath();
- cmSourceGroup* sourceGroup =
- mf->FindSourceGroup(source.c_str(), sourceGroups);
- cmXCodeObject* pbxgroup =
- this->CreateOrGetPBXGroup(gtgt, sourceGroup);
- std::string key = GetGroupMapKeyFromPath(gtgt, source);
- this->GroupMap[key] = pbxgroup;
- }
- }
}
}
return true;
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 56ce2bd..a36e1f6 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -30,7 +30,7 @@ public:
typedef cmComputeLinkInformation::ItemVector ItemVector;
void OutputLibraries(std::ostream& fout, ItemVector const& libs);
void OutputObjects(std::ostream& fout, cmGeneratorTarget* t,
- const char* isep = 0);
+ std::string const& config, const char* isep = 0);
private:
cmLocalVisualStudio7Generator* LocalGenerator;
@@ -1043,7 +1043,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS8 ||
this->FortranProject) {
std::ostringstream libdeps;
- this->Internal->OutputObjects(libdeps, target);
+ this->Internal->OutputObjects(libdeps, target, configName);
if (!libdeps.str().empty()) {
fout << "\t\t\t\tAdditionalDependencies=\"" << libdeps.str()
<< "\"\n";
@@ -1096,7 +1096,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS8 ||
this->FortranProject) {
- this->Internal->OutputObjects(fout, target, " ");
+ this->Internal->OutputObjects(fout, target, configName, " ");
}
fout << " ";
this->Internal->OutputLibraries(fout, cli.GetItems());
@@ -1181,7 +1181,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(
<< this->Makefile->GetSafeDefinition(standardLibsVar.c_str());
if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS8 ||
this->FortranProject) {
- this->Internal->OutputObjects(fout, target, " ");
+ this->Internal->OutputObjects(fout, target, configName, " ");
}
fout << " ";
this->Internal->OutputLibraries(fout, cli.GetItems());
@@ -1300,21 +1300,20 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries(
}
void cmLocalVisualStudio7GeneratorInternals::OutputObjects(
- std::ostream& fout, cmGeneratorTarget* gt, const char* isep)
+ std::ostream& fout, cmGeneratorTarget* gt, std::string const& configName,
+ const char* isep)
{
// VS < 8 does not support per-config source locations so we
// list object library content on the link line instead.
cmLocalVisualStudio7Generator* lg = this->LocalGenerator;
std::string currentBinDir = lg->GetCurrentBinaryDirectory();
- std::vector<cmSourceFile*> sources;
- if (!gt->GetConfigCommonSourceFiles(sources)) {
- return;
- }
+ std::vector<cmSourceFile const*> objs;
+ gt->GetExternalObjects(objs, configName);
const char* sep = isep ? isep : "";
- for (std::vector<cmSourceFile*>::const_iterator i = sources.begin();
- i != sources.end(); i++) {
+ for (std::vector<cmSourceFile const*>::const_iterator i = objs.begin();
+ i != objs.end(); ++i) {
if (!(*i)->GetObjectLibrary().empty()) {
std::string const& objFile = (*i)->GetFullPath();
std::string rel = lg->ConvertToRelativePath(currentBinDir, objFile);
@@ -1369,14 +1368,14 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
// We may be modifying the source groups temporarily, so make a copy.
std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
- // get the classes from the source lists then add them to the groups
- std::vector<cmSourceFile*> classes;
- if (!target->GetConfigCommonSourceFiles(classes)) {
- return;
- }
- for (std::vector<cmSourceFile*>::const_iterator i = classes.begin();
- i != classes.end(); i++) {
- if (!(*i)->GetObjectLibrary().empty()) {
+ std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
+ target->GetAllConfigSources();
+ std::map<cmSourceFile const*, size_t> sourcesIndex;
+
+ for (size_t si = 0; si < sources.size(); ++si) {
+ cmSourceFile const* sf = sources[si].Source;
+ sourcesIndex[sf] = si;
+ if (!sf->GetObjectLibrary().empty()) {
if (this->GetVersion() < cmGlobalVisualStudioGenerator::VS8 ||
this->FortranProject) {
// VS < 8 does not support per-config source locations so we
@@ -1386,10 +1385,10 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
}
}
// Add the file to the list of sources.
- std::string source = (*i)->GetFullPath();
+ std::string const source = sf->GetFullPath();
cmSourceGroup* sourceGroup =
this->Makefile->FindSourceGroup(source.c_str(), sourceGroups);
- sourceGroup->AssignSource(*i);
+ sourceGroup->AssignSource(sf);
}
// open the project
@@ -1402,7 +1401,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout,
// Loop through every source group.
for (unsigned int i = 0; i < sourceGroups.size(); ++i) {
cmSourceGroup sg = sourceGroups[i];
- this->WriteGroup(&sg, target, fout, libName, configs);
+ this->WriteGroup(&sg, target, fout, libName, configs, sourcesIndex);
}
fout << "\t</Files>\n";
@@ -1424,25 +1423,28 @@ struct cmLVS7GFileConfig
class cmLocalVisualStudio7GeneratorFCInfo
{
public:
- cmLocalVisualStudio7GeneratorFCInfo(cmLocalVisualStudio7Generator* lg,
- cmGeneratorTarget* target,
- cmSourceFile const& sf,
- std::vector<std::string> const& configs);
+ cmLocalVisualStudio7GeneratorFCInfo(
+ cmLocalVisualStudio7Generator* lg, cmGeneratorTarget* target,
+ cmGeneratorTarget::AllConfigSource const& acs,
+ std::vector<std::string> const& configs);
std::map<std::string, cmLVS7GFileConfig> FileConfigMap;
};
cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
cmLocalVisualStudio7Generator* lg, cmGeneratorTarget* gt,
- cmSourceFile const& sf, std::vector<std::string> const& configs)
+ cmGeneratorTarget::AllConfigSource const& acs,
+ std::vector<std::string> const& configs)
{
+ cmSourceFile const& sf = *acs.Source;
std::string objectName;
if (gt->HasExplicitObjectName(&sf)) {
objectName = gt->GetObjectName(&sf);
}
// Compute per-source, per-config information.
+ size_t ci = 0;
for (std::vector<std::string>::const_iterator i = configs.begin();
- i != configs.end(); ++i) {
+ i != configs.end(); ++i, ++ci) {
std::string configUpper = cmSystemTools::UpperCase(*i);
cmLVS7GFileConfig fc;
bool needfc = false;
@@ -1508,7 +1510,9 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
}
// If HEADER_FILE_ONLY is set, we must suppress this generation in
// the project file
- fc.ExcludedFromBuild = (sf.GetPropertyAsBool("HEADER_FILE_ONLY"));
+ fc.ExcludedFromBuild = sf.GetPropertyAsBool("HEADER_FILE_ONLY") ||
+ std::find(acs.Configs.begin(), acs.Configs.end(), ci) ==
+ acs.Configs.end();
if (fc.ExcludedFromBuild) {
needfc = true;
}
@@ -1563,7 +1567,8 @@ std::string cmLocalVisualStudio7Generator::ComputeLongestObjectDirectory(
bool cmLocalVisualStudio7Generator::WriteGroup(
const cmSourceGroup* sg, cmGeneratorTarget* target, std::ostream& fout,
- const std::string& libName, std::vector<std::string> const& configs)
+ const std::string& libName, std::vector<std::string> const& configs,
+ std::map<cmSourceFile const*, size_t> const& sourcesIndex)
{
cmGlobalVisualStudio7Generator* gg =
static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator);
@@ -1574,7 +1579,8 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
bool hasChildrenWithSources = false;
std::ostringstream tmpOut;
for (unsigned int i = 0; i < children.size(); ++i) {
- if (this->WriteGroup(&children[i], target, tmpOut, libName, configs)) {
+ if (this->WriteGroup(&children[i], target, tmpOut, libName, configs,
+ sourcesIndex)) {
hasChildrenWithSources = true;
}
}
@@ -1590,15 +1596,26 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
this->WriteVCProjBeginGroup(fout, name.c_str(), "");
}
+ std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
+ target->GetAllConfigSources();
+
// Loop through each source in the source group.
for (std::vector<const cmSourceFile*>::const_iterator sf =
sourceFiles.begin();
sf != sourceFiles.end(); ++sf) {
std::string source = (*sf)->GetFullPath();
- FCInfo fcinfo(this, target, *(*sf), configs);
if (source != libName || target->GetType() == cmStateEnums::UTILITY ||
target->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ // Look up the source kind and configs.
+ std::map<cmSourceFile const*, size_t>::const_iterator map_it =
+ sourcesIndex.find(*sf);
+ // The map entry must exist because we populated it earlier.
+ assert(map_it != sourcesIndex.end());
+ cmGeneratorTarget::AllConfigSource const& acs = sources[map_it->second];
+
+ FCInfo fcinfo(this, target, acs, configs);
+
fout << "\t\t\t<File\n";
std::string d = this->ConvertToXMLOutputPathSingle(source.c_str());
// Tell MS-Dev what the source is. If the compiler knows how to
@@ -1638,6 +1655,9 @@ bool cmLocalVisualStudio7Generator::WriteGroup(
lang == "ASM_MASM") {
aCompilerTool = "MASM";
}
+ if (acs.Kind == cmGeneratorTarget::SourceKindExternalObject) {
+ aCompilerTool = "VCCustomBuildTool";
+ }
for (std::map<std::string, cmLVS7GFileConfig>::const_iterator fci =
fcinfo.FileConfigMap.begin();
fci != fcinfo.FileConfigMap.end(); ++fci) {
diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h
index 2bf38ea..89a3ee3 100644
--- a/Source/cmLocalVisualStudio7Generator.h
+++ b/Source/cmLocalVisualStudio7Generator.h
@@ -119,7 +119,8 @@ private:
bool WriteGroup(const cmSourceGroup* sg, cmGeneratorTarget* target,
std::ostream& fout, const std::string& libName,
- std::vector<std::string> const& configs);
+ std::vector<std::string> const& configs,
+ std::map<cmSourceFile const*, size_t> const& sourcesIndex);
friend class cmLocalVisualStudio7GeneratorFCInfo;
friend class cmLocalVisualStudio7GeneratorInternals;
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index d29a8bd..f297988 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -291,13 +291,10 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
if (this->GetType() != cmStateEnums::UTILITY) {
const char* configProps[] = {
/* clang-format needs this comment to break after the opening brace */
- "ARCHIVE_OUTPUT_DIRECTORY_",
- "LIBRARY_OUTPUT_DIRECTORY_",
- "RUNTIME_OUTPUT_DIRECTORY_",
- "PDB_OUTPUT_DIRECTORY_",
- "COMPILE_PDB_OUTPUT_DIRECTORY_",
- "MAP_IMPORTED_CONFIG_",
- CM_NULLPTR
+ "ARCHIVE_OUTPUT_DIRECTORY_", "LIBRARY_OUTPUT_DIRECTORY_",
+ "RUNTIME_OUTPUT_DIRECTORY_", "PDB_OUTPUT_DIRECTORY_",
+ "COMPILE_PDB_OUTPUT_DIRECTORY_", "MAP_IMPORTED_CONFIG_",
+ "INTERPROCEDURAL_OPTIMIZATION_", CM_NULLPTR
};
for (std::vector<std::string>::iterator ci = configNames.begin();
ci != configNames.end(); ++ci) {
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 8e6014a..fbfc1ed 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1241,16 +1241,15 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
// collect up group information
std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
- std::vector<cmSourceFile*> classes;
- if (!this->GeneratorTarget->GetConfigCommonSourceFiles(classes)) {
- return;
- }
+
+ std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
+ this->GeneratorTarget->GetAllConfigSources();
std::set<cmSourceGroup*> groupsUsed;
- for (std::vector<cmSourceFile*>::const_iterator s = classes.begin();
- s != classes.end(); s++) {
- cmSourceFile* sf = *s;
- std::string const& source = sf->GetFullPath();
+ for (std::vector<cmGeneratorTarget::AllConfigSource>::const_iterator si =
+ sources.begin();
+ si != sources.end(); ++si) {
+ std::string const& source = si->Source->GetFullPath();
cmSourceGroup* sourceGroup =
this->Makefile->FindSourceGroup(source.c_str(), sourceGroups);
groupsUsed.insert(sourceGroup);
@@ -1734,12 +1733,17 @@ void cmVisualStudio10TargetGenerator::WriteAllSources()
}
this->WriteString("<ItemGroup>\n", 1);
- cmGeneratorTarget::KindedSources const& sources =
- this->GeneratorTarget->GetKindedSources("");
+ std::vector<size_t> all_configs;
+ for (size_t ci = 0; ci < this->Configurations.size(); ++ci) {
+ all_configs.push_back(ci);
+ }
+
+ std::vector<cmGeneratorTarget::AllConfigSource> const& sources =
+ this->GeneratorTarget->GetAllConfigSources();
- for (std::vector<cmGeneratorTarget::SourceAndKind>::const_iterator si =
- sources.Sources.begin();
- si != sources.Sources.end(); ++si) {
+ for (std::vector<cmGeneratorTarget::AllConfigSource>::const_iterator si =
+ sources.begin();
+ si != sources.end(); ++si) {
std::string tool;
switch (si->Kind) {
case cmGeneratorTarget::SourceKindAppManifest:
@@ -1810,14 +1814,35 @@ void cmVisualStudio10TargetGenerator::WriteAllSources()
}
if (!tool.empty()) {
+ // Compute set of configurations to exclude, if any.
+ std::vector<size_t> const& include_configs = si->Configs;
+ std::vector<size_t> exclude_configs;
+ std::set_difference(all_configs.begin(), all_configs.end(),
+ include_configs.begin(), include_configs.end(),
+ std::back_inserter(exclude_configs));
+
if (si->Kind == cmGeneratorTarget::SourceKindObjectSource) {
+ // FIXME: refactor generation to avoid tracking XML syntax state.
this->WriteSource(tool, si->Source, " ");
- if (this->OutputSourceSpecificFlags(si->Source)) {
+ bool have_nested = this->OutputSourceSpecificFlags(si->Source);
+ if (!exclude_configs.empty()) {
+ if (!have_nested) {
+ (*this->BuildFileStream) << ">\n";
+ }
+ this->WriteExcludeFromBuild(exclude_configs);
+ have_nested = true;
+ }
+ if (have_nested) {
this->WriteString("</", 2);
(*this->BuildFileStream) << tool << ">\n";
} else {
(*this->BuildFileStream) << " />\n";
}
+ } else if (!exclude_configs.empty()) {
+ this->WriteSource(tool, si->Source, ">\n");
+ this->WriteExcludeFromBuild(exclude_configs);
+ this->WriteString("</", 2);
+ (*this->BuildFileStream) << tool << ">\n";
} else {
this->WriteSource(tool, si->Source);
}
@@ -2001,6 +2026,19 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
return hasFlags;
}
+void cmVisualStudio10TargetGenerator::WriteExcludeFromBuild(
+ std::vector<size_t> const& exclude_configs)
+{
+ for (std::vector<size_t>::const_iterator ci = exclude_configs.begin();
+ ci != exclude_configs.end(); ++ci) {
+ this->WriteString("", 3);
+ (*this->BuildFileStream)
+ << "<ExcludedFromBuild Condition=\"'$(Configuration)|$(Platform)'=='"
+ << cmVS10EscapeXML(this->Configurations[*ci]) << "|"
+ << cmVS10EscapeXML(this->Platform) << "'\">true</ExcludedFromBuild>\n";
+ }
+}
+
void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions()
{
cmStateEnums::TargetType ttype = this->GeneratorTarget->GetType();
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 7432244..bd270bf 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -62,6 +62,7 @@ private:
void WriteNsightTegraConfigurationValues(std::string const& config);
void WriteSource(std::string const& tool, cmSourceFile const* sf,
const char* end = 0);
+ void WriteExcludeFromBuild(std::vector<size_t> const& exclude_configs);
void WriteAllSources();
void WriteDotNetReferences();
void WriteDotNetReference(std::string const& ref, std::string const& hint);
diff --git a/Tests/RunCMake/CMP0026/CMP0026-OLD.cmake b/Tests/RunCMake/CMP0026/CMP0026-OLD.cmake
new file mode 100644
index 0000000..80497a3
--- /dev/null
+++ b/Tests/RunCMake/CMP0026/CMP0026-OLD.cmake
@@ -0,0 +1,12 @@
+enable_language(CXX)
+
+cmake_policy(SET CMP0026 OLD)
+
+set(out ${CMAKE_CURRENT_BINARY_DIR}/out.txt)
+
+add_library(somelib empty.cpp ${out})
+get_target_property(_loc somelib LOCATION)
+
+file(WRITE "${out}"
+ "source file written by project code after getting target LOCATION\n"
+ )
diff --git a/Tests/RunCMake/CMP0026/RunCMakeTest.cmake b/Tests/RunCMake/CMP0026/RunCMakeTest.cmake
index 6331717..047da28 100644
--- a/Tests/RunCMake/CMP0026/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CMP0026/RunCMakeTest.cmake
@@ -1,6 +1,7 @@
include(RunCMake)
run_cmake(CMP0026-WARN)
+run_cmake(CMP0026-OLD)
run_cmake(CMP0026-NEW)
run_cmake(CMP0026-IMPORTED)
run_cmake(CMP0026-CONFIG-LOCATION-NEW)
diff --git a/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad-result.txt b/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad-stderr.txt b/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad-stderr.txt
new file mode 100644
index 0000000..9d5f876
--- /dev/null
+++ b/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad-stderr.txt
@@ -0,0 +1,15 @@
+^CMake Error at INSTALL-FILES_FROM_DIR-bad.cmake:[0-9]+ \(file\):
+ file option FILES_FROM_DIR requires all files to be specified as relative
+ paths\.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Error at INSTALL-FILES_FROM_DIR-bad.cmake:[0-9]+ \(file\):
+ file INSTALL option RENAME may not be combined with FILES_FROM_DIR\.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)
++
+CMake Error at INSTALL-FILES_FROM_DIR-bad.cmake:[0-9]+ \(file\):
+ file option FILES_FROM_DIR may not appear after PATTERN or REGEX\.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad.cmake b/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad.cmake
new file mode 100644
index 0000000..807b704
--- /dev/null
+++ b/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-bad.cmake
@@ -0,0 +1,5 @@
+set(src ${CMAKE_CURRENT_SOURCE_DIR}/from)
+set(dst ${CMAKE_CURRENT_BINARY_DIR}/from)
+file(INSTALL FILES ${src}/a.txt FILES_FROM_DIR ${src} DESTINATION ${dst})
+file(INSTALL FILES a.txt FILES_FROM_DIR ${src} DESTINATION ${dst} RENAME b.txt)
+file(INSTALL FILES a.txt DESTINATION ${dst} PATTERN *.txt FILES_FROM_DIR)
diff --git a/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-stdout.txt b/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-stdout.txt
new file mode 100644
index 0000000..1c3c693
--- /dev/null
+++ b/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-stdout.txt
@@ -0,0 +1,8 @@
+-- Before Installing
+-- Installing: .*/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-build/from/a.txt
+-- Installing: .*/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-build/from/a/b.txt
+-- Installing: .*/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-build/from/a/b/c.txt
+-- Up-to-date: .*/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-build/from/a.txt
+-- Up-to-date: .*/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-build/from/a/b.txt
+-- Up-to-date: .*/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR-build/from/a/b/c.txt
+-- After Installing
diff --git a/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR.cmake b/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR.cmake
new file mode 100644
index 0000000..24e5282
--- /dev/null
+++ b/Tests/RunCMake/file/INSTALL-FILES_FROM_DIR.cmake
@@ -0,0 +1,7 @@
+set(src ${CMAKE_CURRENT_SOURCE_DIR}/from)
+set(dst ${CMAKE_CURRENT_BINARY_DIR}/from)
+file(REMOVE RECURSE ${dst})
+message(STATUS "Before Installing")
+file(INSTALL FILES a.txt a/b.txt a/b/c.txt FILES_FROM_DIR ${src} DESTINATION ${dst})
+file(INSTALL FILES a.txt a/b.txt a/b/c.txt FILES_FROM_DIR from DESTINATION ${dst})
+message(STATUS "After Installing")
diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake
index 63cbdd9..26051b4 100644
--- a/Tests/RunCMake/file/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file/RunCMakeTest.cmake
@@ -8,6 +8,8 @@ run_cmake(UPLOAD-unused-argument)
run_cmake(UPLOAD-httpheader-not-set)
run_cmake(UPLOAD-pass-not-set)
run_cmake(INSTALL-DIRECTORY)
+run_cmake(INSTALL-FILES_FROM_DIR)
+run_cmake(INSTALL-FILES_FROM_DIR-bad)
run_cmake(INSTALL-MESSAGE-bad)
run_cmake(FileOpenFailRead)
run_cmake(LOCK)
diff --git a/Tests/RunCMake/file/from/a.txt b/Tests/RunCMake/file/from/a.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/file/from/a.txt
diff --git a/Tests/RunCMake/file/from/a/b.txt b/Tests/RunCMake/file/from/a/b.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/file/from/a/b.txt
diff --git a/Tests/RunCMake/file/from/a/b/c.txt b/Tests/RunCMake/file/from/a/b/c.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/file/from/a/b/c.txt
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
new file mode 100644
index 0000000..cfa90cc
--- /dev/null
+++ b/Utilities/IWYU/mapping.imp
@@ -0,0 +1,136 @@
+[
+ # C++ alternatives to C standard headers
+ { include: [ "<assert.h>", public, "<cassert>", public ] },
+ { include: [ "<complex.h>", public, "<ccomplex>", public ] },
+ { include: [ "<ctype.h>", public, "<cctype>", public ] },
+ { include: [ "<errno.h>", public, "<cerrno>", public ] },
+ { include: [ "<float.h>", public, "<cfloat>", public ] },
+ { include: [ "<iso646.h>", public, "<ciso646>", public ] },
+ { include: [ "<limits.h>", public, "<climits>", public ] },
+ { include: [ "<locale.h>", public, "<clocale>", public ] },
+ { include: [ "<math.h>", public, "<cmath>", public ] },
+ { include: [ "<setjmp.h>", public, "<csetjmp>", public ] },
+ { include: [ "<signal.h>", public, "<csignal>", public ] },
+ { include: [ "<stdarg.h>", public, "<cstdarg>", public ] },
+ { include: [ "<stddef.h>", public, "<cstddef>", public ] },
+ { include: [ "<stdio.h>", public, "<cstdio>", public ] },
+ { include: [ "<stdlib.h>", public, "<cstdlib>", public ] },
+ { include: [ "<string.h>", public, "<cstring>", public ] },
+ { include: [ "<time.h>", public, "<ctime>", public ] },
+ { include: [ "<wchar.h>", public, "<cwchar>", public ] },
+ { include: [ "<wctype.h>", public, "<cwctype>", public ] },
+
+ # HACK: check whether this can be removed with next iwyu release.
+ { include: [ "<bits/time.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/clock_t.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/struct_timespec.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/struct_timeval.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/struct_tm.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/time_t.h>", private, "<time.h>", public ] },
+
+ # HACK: check whether this can be removed with next iwyu release.
+ { symbol: [ "__GLIBC__", private, "<stdlib.h>", public ] },
+ { symbol: [ "_Noreturn", private, "<stdlib.h>", public ] },
+
+ # HACK: iwyu wrongly thinks that including <iosfwd> is sufficient.
+ { symbol: [ "std::stringstream", private, "<sstream>", public ] },
+ { symbol: [ "std::istringstream", private, "<sstream>", public ] },
+ { symbol: [ "std::ostringstream", private, "<sstream>", public ] },
+
+ # HACK: iwyu suggests those two files each time vector[] is used.
+ # https://github.com/include-what-you-use/include-what-you-use/issues/166
+ { include: [ "<ext/alloc_traits.h>", private, "<vector>", public ] },
+ { include: [ "<memory>", public, "<vector>", public ] },
+
+ # TODO: enable this block and remove some <utility> includes?
+ #{ symbol: [ "std::pair", private, "<utility>", public ] },
+ #{ symbol: [ "std::pair", private, "<map>", public ] },
+ #{ symbol: [ "std::pair", private, "<set>", public ] },
+
+ # Wrappers for headers added in TR1 / C++11
+ # { include: [ "<array>", public, "\"cm_array.hxx\"", public ] },
+ # { include: [ "<functional>", public, "\"cm_functional.hxx\"", public ] },
+ # { include: [ "<memory>", public, "\"cm_memory.hxx\"", public ] },
+ { include: [ "<unordered_map>", public, "\"cm_unordered_map.hxx\"", public ] },
+ { include: [ "<unordered_set>", public, "\"cm_unordered_set.hxx\"", public ] },
+ # { include: [ "<tr1/array>", public, "\"cm_array.hxx\"", public ] },
+ # { include: [ "<tr1/functional>", public, "\"cm_functional.hxx\"", public ] },
+ # { include: [ "<tr1/memory>", public, "\"cm_memory.hxx\"", public ] },
+ { include: [ "<tr1/unordered_map>", public, "\"cm_unordered_map.hxx\"", public ] },
+ { include: [ "<tr1/unordered_set>", public, "\"cm_unordered_set.hxx\"", public ] },
+
+ # KWIML
+ { include: [ "<stdint.h>", public, "\"cm_kwiml.h\"", public ] },
+ { include: [ "<inttypes.h>", public, "\"cm_kwiml.h\"", public ] },
+
+ # Self-sufficient wrapper for <sys/stat.h>
+ { include: [ "<sys/stat.h>", public, "\"cm_sys_stat.h\"", public ] },
+ { symbol: [ "mode_t", private, "\"cm_sys_stat.h\"", public ] },
+
+ # TODO: remove once TR1 / C++11 is required.
+ { include: [ "\"cmsys/hash_fun.hxx\"", private, "\"cm_unordered_map.hxx\"", public ] },
+ { include: [ "\"cmsys/hash_fun.hxx\"", private, "\"cm_unordered_set.hxx\"", public ] },
+ { include: [ "\"cmsys/hash_map.hxx\"", private, "\"cm_unordered_map.hxx\"", public ] },
+ { include: [ "\"cmsys/hash_set.hxx\"", private, "\"cm_unordered_set.hxx\"", public ] },
+ { include: [ "\"cmsys/hashtable.hxx\"", private, "\"cm_unordered_map.hxx\"", public ] },
+ { include: [ "\"cmsys/hashtable.hxx\"", private, "\"cm_unordered_set.hxx\"", public ] },
+
+ # Wrappers for 3rd-party libraries used from the system.
+ { include: [ "<archive.h>", private, "\"cm_libarchive.h\"", public ] },
+ { include: [ "<archive_entry.h>", private, "\"cm_libarchive.h\"", public ] },
+ { include: [ "@<curl/.+\\.h>", private, "\"cm_curl.h\"", public ] },
+ { include: [ "<expat.h>", private, "\"cm_expat.h\"", public ] },
+ { include: [ "<expat_external.h>", private, "\"cm_expat.h\"", public ] },
+ { include: [ "<json/reader.h>", private, "\"cm_jsoncpp_reader.h\"", public ] },
+ { include: [ "<json/value.h>", private, "\"cm_jsoncpp_value.h\"", public ] },
+ { include: [ "<json/writer.h>", private, "\"cm_jsoncpp_writer.h\"", public ] },
+ { include: [ "<rhash.h>", private, "\"cm_rhash.h\"", public ] },
+ { include: [ "<uv.h>", private, "\"cm_uv.h\"", public ] },
+ { include: [ "@<uv-.+\\.h>", private, "\"cm_uv.h\"", public ] },
+ { include: [ "<kwiml/abi.h>", private, "\"cm_kwiml.h\"", public ] },
+ { include: [ "<kwiml/int.h>", private, "\"cm_kwiml.h\"", public ] },
+ { include: [ "<xmlrpc.h>", private, "\"cm_xmlrpc.h\"", public ] },
+ { include: [ "<xmlrpc_client.h>", private, "\"cm_xmlrpc.h\"", public ] },
+ { include: [ "@<xmlrpc-c/.+\\.h>", private, "\"cm_xmlrpc.h\"", public ] },
+ { include: [ "<zconf.h>", private, "\"cm_zlib.h\"", public ] },
+ { include: [ "<zlib.h>", private, "\"cm_zlib.h\"", public ] },
+
+ # Wrappers for bundled 3rd-party libraries.
+ { include: [ "\"cmlibarchive/libarchive/archive.h\"", private, "\"cm_libarchive.h\"", public ] },
+ { include: [ "\"cmlibarchive/libarchive/archive_entry.h\"", private, "\"cm_libarchive.h\"", public ] },
+ { include: [ "@\"cmcurl/include/curl/.+\\.h\"", private, "\"cm_curl.h\"", public ] },
+ { include: [ "\"cmexpat/lib/expat.h\"", private, "\"cm_expat.h\"", public ] },
+ { include: [ "\"cmexpat/lib/expat_external.h\"", private, "\"cm_expat.h\"", public ] },
+ { include: [ "\"cmjsoncpp/include/json/reader.h\"", private, "\"cm_jsoncpp_reader.h\"", public ] },
+ { include: [ "\"cmjsoncpp/include/json/value.h\"", private, "\"cm_jsoncpp_value.h\"", public ] },
+ { include: [ "\"cmjsoncpp/include/json/writer.h\"", private, "\"cm_jsoncpp_writer.h\"", public ] },
+ { include: [ "\"cmlibrhash/librhash/rhash.h\"", private, "\"cm_rhash.h\"", public ] },
+ { include: [ "\"cmlibuv/include/uv.h\"", private, "\"cm_uv.h\"", public ] },
+ { include: [ "@\"cmlibuv/include/uv-.+\\.h\"", private, "\"cm_uv.h\"", public ] },
+ { include: [ "\"KWIML/include/kwiml/abi.h\"", private, "\"cm_kwiml.h\"", public ] },
+ { include: [ "\"KWIML/include/kwiml/int.h\"", private, "\"cm_kwiml.h\"", public ] },
+ { include: [ "\"cmzlib/cm_zlib_mangle.h\"", private, "\"cm_zlib.h\"", public ] },
+ { include: [ "\"cmzlib/zconf.h\"", private, "\"cm_zlib.h\"", public ] },
+ { include: [ "\"cmzlib/zlib.h\"", private, "\"cm_zlib.h\"", public ] },
+
+ { symbol: [ "std::ifstream", private, "\"cmsys/FStream.hxx\"", public ] },
+ { symbol: [ "std::ofstream", private, "\"cmsys/FStream.hxx\"", public ] },
+ { symbol: [ "cmsys::ifstream", private, "\"cmsys/FStream.hxx\"", public ] },
+ { symbol: [ "cmsys::ofstream", private, "\"cmsys/FStream.hxx\"", public ] },
+
+ { include: [ "<istream>", public, "\"cmsys/FStream.hxx\"", public ] },
+ { include: [ "<ostream>", public, "\"cmsys/FStream.hxx\"", public ] },
+ { include: [ "<fstream>", public, "\"cmsys/FStream.hxx\"", public ] },
+
+ # major and minor are used as macro arguments. Those are false matches.
+ { symbol: [ "major", private, "\"cm_kwiml.h\"", public ] },
+ { symbol: [ "minor", private, "\"cm_kwiml.h\"", public ] },
+ { symbol: [ "major", private, "\"cmVersion.h\"", public ] },
+ { symbol: [ "minor", private, "\"cmVersion.h\"", public ] },
+
+ { include: [ "<curses.h>", private, "\"cmCursesStandardIncludes.h\"", public ] },
+ { include: [ "\"form.h\"", private, "\"cmCursesStandardIncludes.h\"", public ] },
+ { include: [ "<form.h>", private, "\"cmCursesStandardIncludes.h\"", public ] },
+]
+
+# vim: set ft=toml: