summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCristian Adam <cristian.adam@gmail.com>2019-09-19 23:56:31 +0200
committerBrad King <brad.king@kitware.com>2019-09-23 11:13:13 -0400
commitacb9511044a230126289c1e99cfed134c3be3c52 (patch)
tree4beb957a681b2baa9095c4f18f0254fbb29555d9
parentebb9346490741ddc2ce6f552bc1be57dfc730cfa (diff)
downloadcmake-acb9511044a230126289c1e99cfed134c3be3c52.tar.gz
Precompile headers: Treat headers as relative to current source directory
Teach `target_precompile_headers` to treat relative paths the same way as `target_sources`. Fixes: #19733
-rw-r--r--Help/command/target_precompile_headers.rst21
-rw-r--r--Source/cmTargetPrecompileHeadersCommand.cxx41
-rw-r--r--Source/cmTargetPrecompileHeadersCommand.h9
-rw-r--r--Tests/RunCMake/PrecompileHeaders/DisabledPch.cmake2
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake13
-rw-r--r--Tests/RunCMake/PrecompileHeaders/PchInterface.cmake5
-rw-r--r--Tests/RunCMake/PrecompileHeaders/foo.c6
-rw-r--r--Tests/RunCMake/PrecompileHeaders/foobar.c3
-rw-r--r--Tests/RunCMake/PrecompileHeaders/include/foo2.h6
9 files changed, 89 insertions, 17 deletions
diff --git a/Help/command/target_precompile_headers.rst b/Help/command/target_precompile_headers.rst
index 7d36b11d7a..3a32f4147e 100644
--- a/Help/command/target_precompile_headers.rst
+++ b/Help/command/target_precompile_headers.rst
@@ -48,17 +48,32 @@ See the :manual:`cmake-generator-expressions(7)` manual for available
expressions. See the :manual:`cmake-compile-features(7)` manual for
information on compile features and a list of supported compilers.
+Usage
+^^^^^
+
.. code-block:: cmake
target_precompile_headers(<target>
PUBLIC
- "project_header.h"
+ project_header.h
PRIVATE
+ [["other_header.h"]]
<unordered_map>
)
-Header files will be double quoted if they are not specified with double
-quotes or angle brackets.
+The list of header files is used to generate a header file named
+``cmake_pch.h|xx`` which is used to generate the precompiled header file
+(``.pch``, ``.gch``, ``.pchi``) artifact. The ``cmake_pch.h|xx`` header
+file will be force included (``-include`` for GCC, ``/FI`` for MSVC) to
+all source files, so sources do not need to have ``#include "pch.h"``.
+
+Header file names specified with angle brackets (e.g. ``<unordered_map>``) or
+explicit double quotes (escaped for the :manual:`cmake-language(7)`,
+e.g. ``[["other_header.h"]]``) will be treated as is, and include directories
+must be available for the compiler to find them. Other header file names
+(e.g. ``project_header.h``) are interpreted as being relative to the current
+source directory (e.g. :variable:`CMAKE_CURRENT_SOURCE_DIR`) and will be
+included by absolute path.
See Also
^^^^^^^^
diff --git a/Source/cmTargetPrecompileHeadersCommand.cxx b/Source/cmTargetPrecompileHeadersCommand.cxx
index 97f1bea5fb..5751fffa19 100644
--- a/Source/cmTargetPrecompileHeadersCommand.cxx
+++ b/Source/cmTargetPrecompileHeadersCommand.cxx
@@ -2,17 +2,29 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTargetPrecompileHeadersCommand.h"
+#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
#include "cmTarget.h"
+#include <utility>
+
bool cmTargetPrecompileHeadersCommand::InitialPass(
std::vector<std::string> const& args, cmExecutionStatus&)
{
return this->HandleArguments(args, "PRECOMPILE_HEADERS", PROCESS_REUSE_FROM);
}
+void cmTargetPrecompileHeadersCommand::HandleInterfaceContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool prepend,
+ bool system)
+{
+ cmTargetPropCommandBase::HandleInterfaceContent(
+ tgt, ConvertToAbsoluteContent(tgt, content, true), prepend, system);
+}
+
void cmTargetPrecompileHeadersCommand::HandleMissingTarget(
const std::string& name)
{
@@ -31,6 +43,33 @@ std::string cmTargetPrecompileHeadersCommand::Join(
bool cmTargetPrecompileHeadersCommand::HandleDirectContent(
cmTarget* tgt, const std::vector<std::string>& content, bool, bool)
{
- tgt->AppendProperty("PRECOMPILE_HEADERS", this->Join(content).c_str());
+ tgt->AppendProperty(
+ "PRECOMPILE_HEADERS",
+ this->Join(ConvertToAbsoluteContent(tgt, content, false)).c_str());
return true;
}
+
+std::vector<std::string>
+cmTargetPrecompileHeadersCommand::ConvertToAbsoluteContent(
+ cmTarget* /*tgt*/, const std::vector<std::string>& content,
+ bool /*isInterfaceContent*/)
+{
+ std::vector<std::string> absoluteContent;
+ absoluteContent.reserve(content.size());
+ for (std::string const& src : content) {
+ std::string absoluteSrc;
+ // Use '<foo.h>' and '"foo.h"' includes and absolute paths as-is.
+ // Interpret relative paths with respect to the source directory.
+ // If the path starts in a generator expression, assume it is absolute.
+ if (cmHasLiteralPrefix(src, "<") || cmHasLiteralPrefix(src, "\"") ||
+ cmSystemTools::FileIsFullPath(src) ||
+ cmGeneratorExpression::Find(src) == 0) {
+ absoluteSrc = src;
+ } else {
+ absoluteSrc =
+ cmStrCat(this->Makefile->GetCurrentSourceDirectory(), '/', src);
+ }
+ absoluteContent.emplace_back(std::move(absoluteSrc));
+ }
+ return absoluteContent;
+}
diff --git a/Source/cmTargetPrecompileHeadersCommand.h b/Source/cmTargetPrecompileHeadersCommand.h
index 7e4558e5e3..00dc9285c0 100644
--- a/Source/cmTargetPrecompileHeadersCommand.h
+++ b/Source/cmTargetPrecompileHeadersCommand.h
@@ -28,6 +28,11 @@ public:
bool InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& status) override;
+protected:
+ void HandleInterfaceContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) override;
+
private:
void HandleMissingTarget(const std::string& name) override;
@@ -36,6 +41,10 @@ private:
bool prepend, bool system) override;
std::string Join(const std::vector<std::string>& content) override;
+
+ std::vector<std::string> ConvertToAbsoluteContent(
+ cmTarget* tgt, const std::vector<std::string>& content,
+ bool isInterfaceContent);
};
#endif
diff --git a/Tests/RunCMake/PrecompileHeaders/DisabledPch.cmake b/Tests/RunCMake/PrecompileHeaders/DisabledPch.cmake
index ee47980b6d..59ee14b9ff 100644
--- a/Tests/RunCMake/PrecompileHeaders/DisabledPch.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/DisabledPch.cmake
@@ -4,7 +4,7 @@ project(DisabledPch C)
add_library(foo foo.c)
target_include_directories(foo PUBLIC include)
target_precompile_headers(foo PUBLIC
- foo.h
+ include/foo.h
<stdio.h>
\"string.h\"
)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake
index cbd6edefcb..caeb22b4a1 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchInterface-check.cmake
@@ -18,19 +18,14 @@ endif()
file(STRINGS ${foo_pch_header} foo_pch_header_strings)
-if (NOT "#include \"foo.h\"" IN_LIST foo_pch_header_strings OR
- NOT "#include <stdio.h>" IN_LIST foo_pch_header_strings OR
- NOT "#include \"string.h\"" IN_LIST foo_pch_header_strings)
- set(RunCMake_TEST_FAILED "Generated foo pch header ${foo_pch_header} has bad content")
+if (NOT foo_pch_header_strings MATCHES ";#include \"[^\"]*PrecompileHeaders/include/foo.h\";#include \"foo2.h\";#include <stdio.h>;#include \"string.h\"(;|$)")
+ set(RunCMake_TEST_FAILED "Generated foo pch header\n ${foo_pch_header}\nhas bad content:\n ${foo_pch_header_strings}")
return()
endif()
file(STRINGS ${foobar_pch_header} foobar_pch_header_strings)
-if (NOT "#include \"foo.h\"" IN_LIST foobar_pch_header_strings OR
- NOT "#include <stdio.h>" IN_LIST foobar_pch_header_strings OR
- NOT "#include \"string.h\"" IN_LIST foobar_pch_header_strings OR
- NOT "#include \"bar.h\"" IN_LIST foobar_pch_header_strings)
- set(RunCMake_TEST_FAILED "Generated foobar pch header ${foobar_pch_header} has bad content")
+if (NOT foobar_pch_header_strings MATCHES ";#include \"[^\"]*PrecompileHeaders/include/foo.h\";#include \"foo2.h\";#include <stdio.h>;#include \"string.h\";#include \"[^\"]*PrecompileHeaders/include/bar.h\"(;|$)")
+ set(RunCMake_TEST_FAILED "Generated foobar pch header\n ${foobar_pch_header}\nhas bad content:\n ${foobar_pch_header_strings}")
return()
endif()
diff --git a/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake b/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake
index 9041b09958..a1e0792738 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake
@@ -4,14 +4,15 @@ project(PchInterface C)
add_library(foo foo.c)
target_include_directories(foo PUBLIC include)
target_precompile_headers(foo PUBLIC
- foo.h
+ include/foo.h
+ \"foo2.h\"
<stdio.h>
\"string.h\"
)
add_library(bar INTERFACE)
target_include_directories(bar INTERFACE include)
-target_precompile_headers(bar INTERFACE bar.h)
+target_precompile_headers(bar INTERFACE include/bar.h)
add_executable(foobar foobar.c)
target_link_libraries(foobar foo bar)
diff --git a/Tests/RunCMake/PrecompileHeaders/foo.c b/Tests/RunCMake/PrecompileHeaders/foo.c
index 974a248654..85ea230fa0 100644
--- a/Tests/RunCMake/PrecompileHeaders/foo.c
+++ b/Tests/RunCMake/PrecompileHeaders/foo.c
@@ -1,6 +1,12 @@
#include "foo.h"
+#include "foo2.h"
int foo()
{
return 0;
}
+
+int foo2()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/PrecompileHeaders/foobar.c b/Tests/RunCMake/PrecompileHeaders/foobar.c
index 6dbf8ce384..7a135eafdb 100644
--- a/Tests/RunCMake/PrecompileHeaders/foobar.c
+++ b/Tests/RunCMake/PrecompileHeaders/foobar.c
@@ -1,7 +1,8 @@
#include "bar.h"
#include "foo.h"
+#include "foo2.h"
int main()
{
- return foo() + bar();
+ return foo() + foo2() + bar();
}
diff --git a/Tests/RunCMake/PrecompileHeaders/include/foo2.h b/Tests/RunCMake/PrecompileHeaders/include/foo2.h
new file mode 100644
index 0000000000..4bf9c8167d
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/include/foo2.h
@@ -0,0 +1,6 @@
+#ifndef foo2_h
+#define foo2_h
+
+int foo2(void);
+
+#endif