diff options
| author | ruki <[email protected]> | 2026-01-27 11:47:53 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-01-27 11:47:53 +0800 |
| commit | efe8fc122c04fb05a80488e39ddb19d802e6a409 (patch) | |
| tree | 3ad925a1a0f31771e7ce20c8c94524f21527445d | |
| parent | b55dade1f55c21c498faa39463c5122b1a3bac22 (diff) | |
| parent | b41e1092c8b309d76ad093ebb519fcdf0a79d7fb (diff) | |
Merge pull request #7266 from xmake-io/pch
fix pch header extension
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 |
