From 8ba2870f97ce1213f4a95f95cee1e6b1369916c2 Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 27 Jan 2026 00:43:47 +0800 Subject: fix pch header extension --- xmake/modules/core/tools/gcc.lua | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/xmake/modules/core/tools/gcc.lua b/xmake/modules/core/tools/gcc.lua index 6fc7a641b..9cc46e9f2 100644 --- a/xmake/modules/core/tools/gcc.lua +++ b/xmake/modules/core/tools/gcc.lua @@ -23,6 +23,7 @@ import("core.base.option") import("core.base.tty") import("core.base.colors") import("core.base.global") +import("core.base.hashset") import("core.cache.memcache") import("core.project.config") import("core.project.policy") @@ -980,13 +981,30 @@ function link(self, objectfiles, targetkind, targetfile, flags, opt) end end +-- check if the file is a header file +function _is_header_file(extension) + 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 + -- make the compile arguments list function compargv(self, sourcefile, objectfile, flags, opt) opt = opt or {} -- is precompiled header or module files? remove the force includes. local extension = path.extension(sourcefile) - if (extension:startswith(".h") or extension == ".inl") then + if _is_header_file(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) -- cgit v1.3.1 From d0fa1e1927c4085921bddfbfda64c767f052098e Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 27 Jan 2026 00:46:04 +0800 Subject: fix pch for cl --- xmake/modules/core/tools/cl.lua | 5 +++-- xmake/modules/core/tools/gcc.lua | 21 ++------------------- xmake/modules/private/utils/toolchain.lua | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 21 deletions(-) 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 9cc46e9f2..d390d8884 100644 --- a/xmake/modules/core/tools/gcc.lua +++ b/xmake/modules/core/tools/gcc.lua @@ -23,10 +23,10 @@ import("core.base.option") import("core.base.tty") import("core.base.colors") import("core.base.global") -import("core.base.hashset") 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") @@ -981,30 +981,13 @@ function link(self, objectfiles, targetkind, targetfile, flags, opt) end end --- check if the file is a header file -function _is_header_file(extension) - 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 - -- make the compile arguments list function compargv(self, sourcefile, objectfile, flags, opt) opt = opt or {} -- is precompiled header or module files? remove the force includes. local extension = path.extension(sourcefile) - if _is_header_file(extension) 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 -- cgit v1.3.1 From b41e1092c8b309d76ad093ebb519fcdf0a79d7fb Mon Sep 17 00:00:00 2001 From: ruki Date: Tue, 27 Jan 2026 22:46:19 +0800 Subject: improve pch test --- .../src/pch_test.inc | 34 +++++++++++ .../src/pch_test.inl | 42 ++++++++++++++ .../src/pch_test.ipp | 28 +++++++++ .../src/pch_test.tcc | 42 ++++++++++++++ .../src/pch_test.tpl | 66 ++++++++++++++++++++++ .../src/test_inc.cpp | 16 ++++++ .../src/test_inl.cpp | 24 ++++++++ .../src/test_ipp.cpp | 15 +++++ .../src/test_tcc.cpp | 28 +++++++++ .../src/test_tpl.cpp | 43 ++++++++++++++ .../precompiled_header_multiple_targets/xmake.lua | 30 ++++++++++ 11 files changed, 368 insertions(+) create mode 100644 tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inc create mode 100644 tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.inl create mode 100644 tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.ipp create mode 100644 tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tcc create mode 100644 tests/projects/c++/precompiled_header_multiple_targets/src/pch_test.tpl create mode 100644 tests/projects/c++/precompiled_header_multiple_targets/src/test_inc.cpp create mode 100644 tests/projects/c++/precompiled_header_multiple_targets/src/test_inl.cpp create mode 100644 tests/projects/c++/precompiled_header_multiple_targets/src/test_ipp.cpp create mode 100644 tests/projects/c++/precompiled_header_multiple_targets/src/test_tcc.cpp create mode 100644 tests/projects/c++/precompiled_header_multiple_targets/src/test_tpl.cpp 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 +#include +#include + +// 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 +class INCMap { +private: + std::map 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 +#include +#include + +// PCH with .inl extension +inline void hello_from_inl() { + std::cout << "Hello from .inl PCH!" << std::endl; +} + +template +class INLProcessor { +private: + std::vector 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 +#include +#include + +// PCH with .ipp extension +inline void hello_from_ipp() { + std::cout << "Hello from .ipp PCH!" << std::endl; +} + +template +class IPPContainer { +private: + std::vector 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 +#include +#include + +// PCH with .tcc extension +inline void hello_from_tcc() { + std::cout << "Hello from .tcc PCH!" << std::endl; +} + +template +class TCCCalculator { +private: + std::list 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(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 +#include +#include + +// PCH with .tpl extension +inline void hello_from_tpl() { + std::cout << "Hello from .tpl PCH!" << std::endl; +} + +template +class TPLProcessor { +private: + std::queue input_queue; + std::stack 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 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 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 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 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 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 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_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 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_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") -- cgit v1.3.1