Skip to content

Commit 3612d26

Browse files
authored
Target Precompile Header (#124)
Initial PCH support for Target
1 parent 7a9516a commit 3612d26

File tree

24 files changed

+550
-35
lines changed

24 files changed

+550
-35
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ _deps
1616
.vscode/
1717
.vs/
1818
.idea/
19+
.cache/
1920

2021
# Files
2122
*.gcov

buildcc/lib/target/cmake/mock_target.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ add_library(mock_target STATIC
1313

1414
# Target friend
1515
src/target/friend/file_extension.cpp
16-
include/target/friend/file_extension.h
1716

1817
# Target
1918
src/target/target.cpp
@@ -22,10 +21,12 @@ add_library(mock_target STATIC
2221

2322
src/target/source.cpp
2423
src/target/include_dir.cpp
24+
src/target/pch.cpp
2525
src/target/lib.cpp
2626
src/target/flags.cpp
2727
src/target/additional_deps.cpp
2828

29+
src/target/compile_pch.cpp
2930
src/target/compile_source.cpp
3031
src/target/link_target.cpp
3132
src/target/build.cpp

buildcc/lib/target/cmake/target.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ set(TARGET_SRCS
3030

3131
src/target/source.cpp
3232
src/target/include_dir.cpp
33+
src/target/pch.cpp
3334
src/target/lib.cpp
3435
src/target/flags.cpp
3536
src/target/additional_deps.cpp
3637

3738
src/target/recheck_states.cpp
3839

40+
src/target/compile_pch.cpp
3941
src/target/compile_source.cpp
4042
src/target/link_target.cpp
4143
src/target/build.cpp

buildcc/lib/target/include/target/target.h

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,15 @@ class Target : public BuilderInterface {
6161

6262
std::string target_ext{""};
6363
std::string obj_ext{".o"};
64+
std::string pch_header_ext{".hpp"};
65+
std::string pch_compile_ext{".gch"};
6466

6567
std::string prefix_include_dir{"-I"};
6668
std::string prefix_lib_dir{"-L"};
6769

70+
std::string pch_command{"{compiler} {preprocessor_flags} {include_dirs} "
71+
"{common_compile_flags} {pch_flags} "
72+
"{compile_flags} -o {output} -c {input}"};
6873
std::string compile_command{
6974
"{compiler} {preprocessor_flags} {include_dirs} {common_compile_flags} "
7075
"{compile_flags} -o {output} -c {input}"};
@@ -101,7 +106,6 @@ class Target : public BuilderInterface {
101106
}
102107
virtual ~Target() {}
103108

104-
Target(Target &&target) = default;
105109
Target(const Target &target) = delete;
106110

107111
// Builders
@@ -129,6 +133,11 @@ class Target : public BuilderInterface {
129133
void GlobHeaders(const fs::path &relative_to_target_path);
130134
void GlobHeadersAbsolute(const fs::path &absolute_path);
131135

136+
// PCH
137+
void AddPch(const fs::path &relative_filename,
138+
const fs::path &relative_to_target_path = "");
139+
void AddPchAbsolute(const fs::path &absolute_filepath);
140+
132141
// * Include and Lib directory
133142
void AddIncludeDir(const fs::path &relative_include_dir,
134143
bool glob_headers = false);
@@ -145,6 +154,7 @@ class Target : public BuilderInterface {
145154
// * Flags
146155
void AddPreprocessorFlag(const std::string &flag);
147156
void AddCommonCompileFlag(const std::string &flag);
157+
void AddPchFlag(const std::string &flag);
148158
void AddAsmCompileFlag(const std::string &flag);
149159
void AddCCompileFlag(const std::string &flag);
150160
void AddCppCompileFlag(const std::string &flag);
@@ -177,6 +187,17 @@ class Target : public BuilderInterface {
177187
// we can cache these variables during Target construction
178188
fs::path GetTargetPath() const { return ConstructTargetPath(); }
179189

190+
// TODO, Make these construct APIs
191+
fs::path GetPchHeaderPath() const {
192+
return target_intermediate_dir_ /
193+
fmt::format("buildcc_pch{}", config_.pch_header_ext);
194+
}
195+
// Each target only has only 1 PCH file
196+
fs::path GetPchCompilePath() const {
197+
return GetPchHeaderPath().replace_extension(
198+
fmt::format("{}{}", config_.pch_header_ext, config_.pch_compile_ext));
199+
}
200+
180201
// Const references
181202

182203
// TODO, Shift getters to source file as well
@@ -207,6 +228,9 @@ class Target : public BuilderInterface {
207228
const std::unordered_set<std::string> &GetCurrentCommonCompileFlags() const {
208229
return current_common_compile_flags_;
209230
}
231+
const std::unordered_set<std::string> &GetCurrentPchFlags() const {
232+
return current_pch_flags_;
233+
}
210234
const std::unordered_set<std::string> &GetCurrentAsmCompileFlags() const {
211235
return current_asm_compile_flags_;
212236
}
@@ -273,11 +297,15 @@ class Target : public BuilderInterface {
273297
void UnlockedAfterBuild() const;
274298

275299
// Build
300+
void BuildPch();
301+
// TODO, Rename to BuildObject
276302
void BuildCompile(std::vector<fs::path> &source_files,
277303
std::vector<fs::path> &dummy_source_files);
278304
void BuildLink();
279305

280306
//
307+
void PrePchCompile();
308+
// TODO, Rename to PreObjectCompile
281309
void PreCompile();
282310
void PreLink();
283311

@@ -298,6 +326,8 @@ class Target : public BuilderInterface {
298326
const std::unordered_set<std::string> &current_external_libs);
299327

300328
// Tasks
329+
void PchTask();
330+
// TODO, Rename to ObjectTask and TargetTask
301331
void CompileTask();
302332
void LinkTask();
303333

@@ -319,6 +349,7 @@ class Target : public BuilderInterface {
319349
// Construct
320350
fs::path ConstructObjectPath(const fs::path &absolute_source_file) const;
321351
fs::path ConstructTargetPath() const;
352+
std::string ConstructPchCompileCommand() const;
322353
std::string
323354
ConstructCompileCommand(const fs::path &absolute_current_source) const;
324355
std::string ConstructLinkCommand() const;
@@ -344,12 +375,14 @@ class Target : public BuilderInterface {
344375
// TODO, Use an internal::Storer class / struct for this to reduce clutter
345376
internal::default_files current_source_files_;
346377
internal::default_files current_header_files_;
378+
internal::default_files current_pch_files_;
347379
internal::default_files current_lib_deps_;
348380
internal::fs_unordered_set current_include_dirs_;
349381
internal::fs_unordered_set current_lib_dirs_;
350382
std::unordered_set<std::string> current_external_lib_deps_;
351383
std::unordered_set<std::string> current_preprocessor_flags_;
352384
std::unordered_set<std::string> current_common_compile_flags_;
385+
std::unordered_set<std::string> current_pch_flags_;
353386
std::unordered_set<std::string> current_asm_compile_flags_;
354387
std::unordered_set<std::string> current_c_compile_flags_;
355388
std::unordered_set<std::string> current_cpp_compile_flags_;
@@ -360,6 +393,8 @@ class Target : public BuilderInterface {
360393
// Not used for serialization
361394
// NOTE, Always store the absolute source path -> absolute compiled source
362395
// path here
396+
OutputInfo pch_file_;
397+
// TODO, Remove current from these
363398
std::unordered_map<fs::path, OutputInfo, internal::PathHash>
364399
current_object_files_;
365400
OutputInfo current_target_file_;
@@ -369,6 +404,7 @@ class Target : public BuilderInterface {
369404
FileExt ext_{*this};
370405

371406
tf::Taskflow tf_;
407+
tf::Task pch_task_;
372408
tf::Task compile_task_;
373409
tf::Task link_task_;
374410
};

buildcc/lib/target/include/target/target_loader.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class TargetLoader : public LoaderInterface {
4747

4848
const path_unordered_set &GetLoadedSources() const { return loaded_sources_; }
4949
const path_unordered_set &GetLoadedHeaders() const { return loaded_headers_; }
50+
const path_unordered_set &GetLoadedPchs() const { return loaded_pchs_; }
5051
const path_unordered_set &GetLoadedLibDeps() const {
5152
return loaded_lib_deps_;
5253
}
@@ -64,6 +65,9 @@ class TargetLoader : public LoaderInterface {
6465
const std::unordered_set<std::string> &GetLoadedCommonCompileFlags() const {
6566
return loaded_common_compile_flags_;
6667
}
68+
const std::unordered_set<std::string> &GetLoadedPchFlags() const {
69+
return loaded_pch_flags_;
70+
}
6771
const std::unordered_set<std::string> &GetLoadedAsmCompileFlags() const {
6872
return loaded_asm_compile_flags_;
6973
}
@@ -93,6 +97,7 @@ class TargetLoader : public LoaderInterface {
9397

9498
path_unordered_set loaded_sources_;
9599
path_unordered_set loaded_headers_;
100+
path_unordered_set loaded_pchs_;
96101
path_unordered_set loaded_lib_deps_;
97102

98103
std::unordered_set<std::string> loaded_external_lib_dirs_;
@@ -102,6 +107,7 @@ class TargetLoader : public LoaderInterface {
102107

103108
std::unordered_set<std::string> loaded_preprocessor_flags_;
104109
std::unordered_set<std::string> loaded_common_compile_flags_;
110+
std::unordered_set<std::string> loaded_pch_flags_;
105111
std::unordered_set<std::string> loaded_asm_compile_flags_;
106112
std::unordered_set<std::string> loaded_c_compile_flags_;
107113
std::unordered_set<std::string> loaded_cpp_compile_flags_;

buildcc/lib/target/mock/target/tasks.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace buildcc::base {
44

5+
void Target::PchTask() { BuildPch(); }
6+
57
void Target::CompileTask() {
68
std::vector<fs::path> source_files;
79
std::vector<fs::path> dummy_source_files;

buildcc/lib/target/src/target/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
- [x] `include_dir.cpp`
1818
- Include Dir
1919
- Header File
20+
- [x] `pch.cpp`
21+
- Precompile Header files
2022
- [x] `lib.cpp`
2123
- Lib Dir
2224
- Lib File (full path Target supplied)
@@ -55,7 +57,7 @@
5557

5658
## Action on Target
5759

58-
- [ ] `compile_header.cpp` (pch)
60+
- [x] `compile_header.cpp` (pch)
5961
- [x] `compile_source.cpp` (object)
6062
- [x] `link_target.cpp` (executable, library, C++20 module)
6163
- [x] `build.cpp`

buildcc/lib/target/src/target/build.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,25 @@ void Target::Build() {
5858
{"linker", toolchain_.GetLinker()},
5959
});
6060

61+
// Load the serialized file
62+
(void)loader_.Load();
63+
64+
// PCH Compile
65+
if (!current_pch_files_.user.empty()) {
66+
// TODO, Update .output at Constructor
67+
pch_file_.command = ConstructPchCompileCommand();
68+
PchTask();
69+
}
70+
6171
// Compile Command
72+
// Link Command
6273
for (auto &object_rel : current_object_files_) {
6374
object_rel.second.command = ConstructCompileCommand(object_rel.first);
6475
}
76+
CompileTask();
6577

66-
// Link Command
78+
// TODO, Update .output at Constructor
6779
current_target_file_.command = ConstructLinkCommand();
68-
69-
// Load the serialized file
70-
(void)loader_.Load();
71-
72-
// Register the tasks
73-
CompileTask();
7480
LinkTask();
7581
}
7682

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright 2021 Niket Naidu. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "target/target.h"
18+
19+
#include "env/assert_fatal.h"
20+
#include "env/util.h"
21+
#include "target/util.h"
22+
23+
namespace {
24+
25+
constexpr const char *const kFormat = R"(// Generated by BuildCC
26+
#pragma once
27+
28+
// clang-format off
29+
{aggregated_includes}
30+
)";
31+
32+
void AggregateToFile(const fs::path &filename,
33+
const buildcc::internal::fs_unordered_set &header_files) {
34+
std::string aggregated_includes;
35+
for (const auto &hf : header_files) {
36+
std::string temp = fmt::format("#include \"{}\"\r\n", hf.string());
37+
aggregated_includes.append(temp);
38+
}
39+
40+
buildcc::Command command;
41+
std::string constructed_output = command.Construct(
42+
kFormat, {
43+
{"aggregated_includes", aggregated_includes},
44+
});
45+
bool success = buildcc::env::SaveFile(filename.string().c_str(),
46+
constructed_output, false);
47+
buildcc::env::assert_fatal(success, "Could not save pch file");
48+
}
49+
50+
} // namespace
51+
52+
namespace buildcc::base {
53+
54+
std::string Target::ConstructPchCompileCommand() const {
55+
const std::string compiler = GetState().contains_cpp_src
56+
? GetToolchain().GetCppCompiler()
57+
: GetToolchain().GetCCompiler();
58+
const FileExt::Type file_ext_type =
59+
GetState().contains_cpp_src ? FileExt::Type::Cpp : FileExt::Type::C;
60+
const std::string compile_flags =
61+
ext_.GetCompileFlags(file_ext_type).value_or("");
62+
return command_.Construct(
63+
config_.pch_command,
64+
{
65+
{"compiler", compiler},
66+
{"pch_flags", internal::aggregate(current_pch_flags_)},
67+
{"compile_flags", compile_flags},
68+
{"output", GetPchCompilePath().string()},
69+
{"input", GetPchHeaderPath().string()},
70+
});
71+
}
72+
73+
void Target::PrePchCompile() {
74+
for (const auto &user_pf : current_pch_files_.user) {
75+
current_pch_files_.internal.emplace(
76+
buildcc::internal::Path::CreateExistingPath(user_pf));
77+
}
78+
}
79+
80+
void Target::BuildPch() {
81+
PrePchCompile();
82+
if (!loader_.IsLoaded()) {
83+
dirty_ = true;
84+
} else {
85+
RecheckFlags(loader_.GetLoadedPreprocessorFlags(),
86+
current_preprocessor_flags_);
87+
RecheckFlags(loader_.GetLoadedCommonCompileFlags(),
88+
current_common_compile_flags_);
89+
RecheckFlags(loader_.GetLoadedPchFlags(), current_pch_flags_);
90+
RecheckFlags(loader_.GetLoadedCCompileFlags(), current_c_compile_flags_);
91+
RecheckFlags(loader_.GetLoadedCppCompileFlags(),
92+
current_cpp_compile_flags_);
93+
RecheckDirs(loader_.GetLoadedIncludeDirs(), current_include_dirs_);
94+
RecheckPaths(loader_.GetLoadedHeaders(), current_header_files_.internal);
95+
RecheckPaths(loader_.GetLoadedPchs(), current_pch_files_.internal);
96+
}
97+
98+
if (dirty_) {
99+
AggregateToFile(GetPchHeaderPath(), current_pch_files_.user);
100+
bool success = Command::Execute(pch_file_.command);
101+
env::assert_fatal(success, "Failed to compile pch");
102+
}
103+
}
104+
105+
} // namespace buildcc::base

0 commit comments

Comments
 (0)