summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-01-27 11:47:53 +0800
committerGitHub <[email protected]>2026-01-27 11:47:53 +0800
commitefe8fc122c04fb05a80488e39ddb19d802e6a409 (patch)
tree3ad925a1a0f31771e7ce20c8c94524f21527445d
parentb55dade1f55c21c498faa39463c5122b1a3bac22 (diff)
parentb41e1092c8b309d76ad093ebb519fcdf0a79d7fb (diff)
Merge pull request #7266 from xmake-io/pch
fix pch header extension
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inc34
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inl42
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.ipp28
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tcc42
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tpl66
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/src/test_inc.cpp16
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/src/test_inl.cpp24
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/src/test_ipp.cpp15
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/src/test_tcc.cpp28
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/src/test_tpl.cpp43
-rw-r--r--tests/projects/c++/precompiled_header_multiple_targets/xmake.lua30
-rw-r--r--xmake/modules/core/tools/cl.lua5
-rw-r--r--xmake/modules/core/tools/gcc.lua3
-rw-r--r--xmake/modules/private/utils/toolchain.lua19
14 files changed, 392 insertions, 3 deletions
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inc b/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inc
new file mode 100644
index 000000000..b453e4d03
--- /dev/null
+++ b/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inc
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <iostream>
+#include <string>
+#include <map>
+
+// PCH with .inc extension
+#define APP_NAME "PCH Test"
+#define VERSION "1.0"
+
+inline void hello_from_inc() {
+ std::cout << "Hello from .inc PCH!" << std::endl;
+}
+
+template<typename K, typename V>
+class INCMap {
+private:
+ std::map<K, V> data;
+
+public:
+ void insert(const K& key, const V& value) {
+ data[key] = value;
+ }
+
+ V get(const K& key) const {
+ auto it = data.find(key);
+ return (it != data.end()) ? it->second : V();
+ }
+
+ void print_info() const {
+ std::cout << APP_NAME << " v" << VERSION << std::endl;
+ std::cout << "Map contains " << data.size() << " items" << std::endl;
+ }
+};
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inl b/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inl
new file mode 100644
index 000000000..e624ac21d
--- /dev/null
+++ b/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inl
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <iostream>
+#include <vector>
+#include <algorithm>
+
+// PCH with .inl extension
+inline void hello_from_inl() {
+ std::cout << "Hello from .inl PCH!" << std::endl;
+}
+
+template<typename T>
+class INLProcessor {
+private:
+ std::vector<T> items;
+
+public:
+ void add(const T& item) {
+ items.push_back(item);
+ }
+
+ void sort() {
+ std::sort(items.begin(), items.end());
+ }
+
+ T max() const {
+ if (items.empty()) return T();
+ return *std::max_element(items.begin(), items.end());
+ }
+
+ T min() const {
+ if (items.empty()) return T();
+ return *std::min_element(items.begin(), items.end());
+ }
+
+ void print() const {
+ for (const auto& item : items) {
+ std::cout << item << " ";
+ }
+ std::cout << std::endl;
+ }
+};
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.ipp b/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.ipp
new file mode 100644
index 000000000..188267a5d
--- /dev/null
+++ b/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.ipp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+// PCH with .ipp extension
+inline void hello_from_ipp() {
+ std::cout << "Hello from .ipp PCH!" << std::endl;
+}
+
+template<typename T>
+class IPPContainer {
+private:
+ std::vector<T> data;
+
+public:
+ void add(const T& item) {
+ data.push_back(item);
+ }
+
+ void print() const {
+ for (const auto& item : data) {
+ std::cout << item << " ";
+ }
+ std::cout << std::endl;
+ }
+};
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tcc b/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tcc
new file mode 100644
index 000000000..245ae4979
--- /dev/null
+++ b/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tcc
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <iostream>
+#include <list>
+#include <numeric>
+
+// PCH with .tcc extension
+inline void hello_from_tcc() {
+ std::cout << "Hello from .tcc PCH!" << std::endl;
+}
+
+template<typename T>
+class TCCCalculator {
+private:
+ std::list<T> values;
+
+public:
+ void add(const T& value) {
+ values.push_back(value);
+ }
+
+ T sum() const {
+ return std::accumulate(values.begin(), values.end(), T(0));
+ }
+
+ double average() const {
+ if (values.empty()) return 0.0;
+ return static_cast<double>(sum()) / values.size();
+ }
+
+ void clear() {
+ values.clear();
+ }
+
+ void print() const {
+ std::cout << "Values: ";
+ for (const auto& value : values) {
+ std::cout << value << " ";
+ }
+ std::cout << std::endl;
+ }
+};
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tpl b/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tpl
new file mode 100644
index 000000000..2eaf440c8
--- /dev/null
+++ b/tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tpl
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <iostream>
+#include <queue>
+#include <stack>
+
+// PCH with .tpl extension
+inline void hello_from_tpl() {
+ std::cout << "Hello from .tpl PCH!" << std::endl;
+}
+
+template<typename T>
+class TPLProcessor {
+private:
+ std::queue<T> input_queue;
+ std::stack<T> output_stack;
+
+public:
+ void enqueue(const T& item) {
+ input_queue.push(item);
+ }
+
+ T dequeue() {
+ if (input_queue.empty()) return T();
+ T item = input_queue.front();
+ input_queue.pop();
+ return item;
+ }
+
+ void push_to_stack(const T& item) {
+ output_stack.push(item);
+ }
+
+ T pop_from_stack() {
+ if (output_stack.empty()) return T();
+ T item = output_stack.top();
+ output_stack.pop();
+ return item;
+ }
+
+ void transfer_to_stack() {
+ while (!input_queue.empty()) {
+ push_to_stack(dequeue());
+ }
+ }
+
+ void print_queue() const {
+ std::queue<T> temp = input_queue;
+ std::cout << "Queue: ";
+ while (!temp.empty()) {
+ std::cout << temp.front() << " ";
+ temp.pop();
+ }
+ std::cout << std::endl;
+ }
+
+ void print_stack() const {
+ std::stack<T> temp = output_stack;
+ std::cout << "Stack: ";
+ while (!temp.empty()) {
+ std::cout << temp.top() << " ";
+ temp.pop();
+ }
+ std::cout << std::endl;
+ }
+};
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/src/test_inc.cpp b/tests/projects/c++/precompiled_header_multiple_targets/src/test_inc.cpp
new file mode 100644
index 000000000..07ae74a1a
--- /dev/null
+++ b/tests/projects/c++/precompiled_header_multiple_targets/src/test_inc.cpp
@@ -0,0 +1,16 @@
+#include "pch_test.inc"
+
+int main() {
+ hello_from_inc();
+
+ INCMap<std::string, int> scores;
+ scores.insert("alice", 95);
+ scores.insert("bob", 87);
+ scores.insert("charlie", 92);
+
+ scores.print_info();
+ std::cout << "Alice's score: " << scores.get("alice") << std::endl;
+ std::cout << "Bob's score: " << scores.get("bob") << std::endl;
+
+ return 0;
+}
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/src/test_inl.cpp b/tests/projects/c++/precompiled_header_multiple_targets/src/test_inl.cpp
new file mode 100644
index 000000000..44127b49d
--- /dev/null
+++ b/tests/projects/c++/precompiled_header_multiple_targets/src/test_inl.cpp
@@ -0,0 +1,24 @@
+#include "pch_test.inl"
+
+int main() {
+ hello_from_inl();
+
+ INLProcessor<int> processor;
+ processor.add(42);
+ processor.add(17);
+ processor.add(89);
+ processor.add(3);
+ processor.add(56);
+
+ std::cout << "Original: ";
+ processor.print();
+
+ processor.sort();
+ std::cout << "Sorted: ";
+ processor.print();
+
+ std::cout << "Min: " << processor.min() << std::endl;
+ std::cout << "Max: " << processor.max() << std::endl;
+
+ return 0;
+}
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/src/test_ipp.cpp b/tests/projects/c++/precompiled_header_multiple_targets/src/test_ipp.cpp
new file mode 100644
index 000000000..3a08baf33
--- /dev/null
+++ b/tests/projects/c++/precompiled_header_multiple_targets/src/test_ipp.cpp
@@ -0,0 +1,15 @@
+#include "pch_test.ipp"
+
+int main() {
+ hello_from_ipp();
+
+ IPPContainer<int> container;
+ container.add(1);
+ container.add(2);
+ container.add(3);
+
+ std::cout << "Container contents: ";
+ container.print();
+
+ return 0;
+}
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/src/test_tcc.cpp b/tests/projects/c++/precompiled_header_multiple_targets/src/test_tcc.cpp
new file mode 100644
index 000000000..0a41c9e39
--- /dev/null
+++ b/tests/projects/c++/precompiled_header_multiple_targets/src/test_tcc.cpp
@@ -0,0 +1,28 @@
+#include "pch_test.tcc"
+
+int main() {
+ hello_from_tcc();
+
+ TCCCalculator<double> calc;
+ calc.add(3.5);
+ calc.add(7.2);
+ calc.add(1.8);
+ calc.add(9.6);
+ calc.add(4.1);
+
+ calc.print();
+ std::cout << "Sum: " << calc.sum() << std::endl;
+ std::cout << "Average: " << calc.average() << std::endl;
+
+ // Test with integers
+ TCCCalculator<int> int_calc;
+ int_calc.add(10);
+ int_calc.add(20);
+ int_calc.add(30);
+
+ int_calc.print();
+ std::cout << "Sum: " << int_calc.sum() << std::endl;
+ std::cout << "Average: " << int_calc.average() << std::endl;
+
+ return 0;
+}
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/src/test_tpl.cpp b/tests/projects/c++/precompiled_header_multiple_targets/src/test_tpl.cpp
new file mode 100644
index 000000000..ddb28705e
--- /dev/null
+++ b/tests/projects/c++/precompiled_header_multiple_targets/src/test_tpl.cpp
@@ -0,0 +1,43 @@
+#include "pch_test.tpl"
+
+int main() {
+ hello_from_tpl();
+
+ TPLProcessor<std::string> processor;
+
+ // Add items to queue
+ processor.enqueue("first");
+ processor.enqueue("second");
+ processor.enqueue("third");
+
+ processor.print_queue();
+
+ // Transfer to stack
+ processor.transfer_to_stack();
+ processor.print_queue();
+ processor.print_stack();
+
+ // Pop from stack (LIFO order)
+ std::cout << "Popping from stack:" << std::endl;
+ while (true) {
+ std::string item = processor.pop_from_stack();
+ if (item.empty()) break;
+ std::cout << " " << item << std::endl;
+ }
+
+ // Test with integers
+ TPLProcessor<int> int_processor;
+ int_processor.enqueue(100);
+ int_processor.enqueue(200);
+ int_processor.enqueue(300);
+
+ int_processor.transfer_to_stack();
+ std::cout << "Integer stack pop:" << std::endl;
+ while (true) {
+ int item = int_processor.pop_from_stack();
+ if (item == 0) break;
+ std::cout << " " << item << std::endl;
+ }
+
+ return 0;
+}
diff --git a/tests/projects/c++/precompiled_header_multiple_targets/xmake.lua b/tests/projects/c++/precompiled_header_multiple_targets/xmake.lua
index a3dacda41..2066ecd60 100644
--- a/tests/projects/c++/precompiled_header_multiple_targets/xmake.lua
+++ b/tests/projects/c++/precompiled_header_multiple_targets/xmake.lua
@@ -36,3 +36,33 @@ target("consumer")
set_kind("binary")
add_files("src/consumer.cpp")
add_deps("lib1")
+
+-- Target 7: PCH with .ipp extension
+target("test_ipp_pch")
+ set_kind("binary")
+ set_pcxxheader("src/pch_test.ipp")
+ add_files("src/test_ipp.cpp")
+
+-- Target 8: PCH with .inc extension
+target("test_inc_pch")
+ set_kind("binary")
+ set_pcxxheader("src/pch_test.inc")
+ add_files("src/test_inc.cpp")
+
+-- Target 9: PCH with .inl extension
+target("test_inl_pch")
+ set_kind("binary")
+ set_pcxxheader("src/pch_test.inl")
+ add_files("src/test_inl.cpp")
+
+-- Target 10: PCH with .tcc extension
+target("test_tcc_pch")
+ set_kind("binary")
+ set_pcxxheader("src/pch_test.tcc")
+ add_files("src/test_tcc.cpp")
+
+-- Target 11: PCH with .tpl extension
+target("test_tpl_pch")
+ set_kind("binary")
+ set_pcxxheader("src/pch_test.tpl")
+ add_files("src/test_tpl.cpp")
diff --git a/xmake/modules/core/tools/cl.lua b/xmake/modules/core/tools/cl.lua
index 34be37513..a28d049c3 100644
--- a/xmake/modules/core/tools/cl.lua
+++ b/xmake/modules/core/tools/cl.lua
@@ -26,6 +26,7 @@ import("core.cache.memcache")
import("core.project.project")
import("core.project.policy")
import("core.language.language")
+import("private.utils.toolchain", {alias = "toolchain_utils"})
import("private.tools.vstool")
import("core.tools.cl.parse_include")
import("private.cache.build_cache")
@@ -557,7 +558,7 @@ function _preprocess(program, argv, opt)
flag:startswith("-external:") or flag:startswith("/external:") then
skipped = 1
-- @note we cannot ignore precompiled flags when compiling pch, @see https://github.com/xmake-io/xmake/issues/2885
- elseif not extension:startswith(".h") and (
+ elseif not toolchain_utils.is_cxx_headerext(extension) and (
flag:startswith("-Yu") or flag:startswith("/Yu") or
flag:startswith("-FI") or flag:startswith("/FI") or
flag:startswith("-Fp") or flag:startswith("/Fp")) then
@@ -671,7 +672,7 @@ function compargv(self, sourcefile, objectfile, flags, opt)
-- precompiled header?
local extension = path.extension(sourcefile)
- if (extension:startswith(".h") or extension == ".inl") then
+ if toolchain_utils.is_cxx_headerext(extension) then
return _compargv_pch(self, sourcefile, objectfile, flags)
end
diff --git a/xmake/modules/core/tools/gcc.lua b/xmake/modules/core/tools/gcc.lua
index 6fc7a641b..d390d8884 100644
--- a/xmake/modules/core/tools/gcc.lua
+++ b/xmake/modules/core/tools/gcc.lua
@@ -26,6 +26,7 @@ import("core.base.global")
import("core.cache.memcache")
import("core.project.config")
import("core.project.policy")
+import("private.utils.toolchain", {alias = "toolchain_utils"})
import("core.project.project")
import("core.language.language")
import("utils.progress")
@@ -986,7 +987,7 @@ function compargv(self, sourcefile, objectfile, flags, opt)
-- is precompiled header or module files? remove the force includes.
local extension = path.extension(sourcefile)
- if (extension:startswith(".h") or extension == ".inl") then
+ if toolchain_utils.is_cxx_headerext(extension) then
flags = _translate_flags_for_pch(self, flags)
elseif support.has_module_extension(sourcefile, {extension = extension}) then
flags = _translate_flags_for_mpp(self, flags)
diff --git a/xmake/modules/private/utils/toolchain.lua b/xmake/modules/private/utils/toolchain.lua
index 263137300..b1a26b8da 100644
--- a/xmake/modules/private/utils/toolchain.lua
+++ b/xmake/modules/private/utils/toolchain.lua
@@ -22,6 +22,7 @@
import("core.base.option")
import("core.project.config")
import("core.base.semver")
+import("core.base.hashset")
import("core.tool.linker")
import("core.tool.compiler")
import("core.language.language")
@@ -555,3 +556,21 @@ function get_sanitizer_flags(target, opt)
end
return result
end
+
+-- check if the file is a c++ header file extension
+function is_cxx_headerext(extension)
+ -- prioritize .h* extensions to filter out most cases quickly
+ if extension:startswith(".h") then
+ return true
+ end
+
+ local headerexts = _g.headerexts
+ if not headerexts then
+ local other_header_extensions = {
+ ".inl", ".ipp", ".tcc", ".tpl", ".inc"
+ }
+ headerexts = hashset.from(other_header_extensions)
+ _g.headerexts = headerexts
+ end
+ return headerexts:has(extension) or false
+end