Skip to content

Commit 1215e56

Browse files
authored
MinGW specialized toolchain and target (#179)
1 parent 1798889 commit 1215e56

40 files changed

+826
-6
lines changed

buildcc/buildcc.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021 Niket Naidu. All rights reserved.
2+
* Copyright 2021-2022 Niket Naidu. All rights reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,12 +37,14 @@
3737
// Specialized Toolchain
3838
#include "toolchains/toolchain_gcc.h"
3939
#include "toolchains/toolchain_msvc.h"
40+
#include "toolchains/toolchain_mingw.h"
4041

4142
// TODO, Add more specialized toolchains here
4243

4344
// Specialized Targets
4445
#include "targets/target_gcc.h"
4546
#include "targets/target_msvc.h"
47+
#include "targets/target_mingw.h"
4648
#include "targets/target_generic.h"
4749
#include "targets/target_custom.h"
4850

buildcc/targets/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set(TARGET_SPECIALIZED_SRCS
55
# Specialized targets
66
include/targets/target_gcc.h
77
include/targets/target_msvc.h
8+
include/targets/target_mingw.h
89

910
# User targets
1011
include/targets/target_generic.h
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2021-2022 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+
#ifndef TARGETS_TARGET_MINGW_H_
18+
#define TARGETS_TARGET_MINGW_H_
19+
20+
#include "target/target.h"
21+
22+
#include "target_config_interface.h"
23+
#include "target_gcc.h"
24+
25+
// MinGW
26+
// ".exe", ".a", ".so" -> (x86_64-w64-mingw32)
27+
namespace buildcc {
28+
29+
// Extensions
30+
constexpr const char *const kMingwExecutableExt = ".exe";
31+
constexpr const char *const kMingwDynamicLibExt = ".dll";
32+
33+
constexpr const char *const kMingwDynamicLibLinkCommand =
34+
"{cpp_compiler} -shared {link_flags} {compiled_sources} -o {output} "
35+
"-Wl,--out-implib,{output}.a";
36+
37+
class MingwConfig : ConfigInterface<MingwConfig> {
38+
public:
39+
static TargetConfig Executable() {
40+
return DefaultMingwConfig(kMingwExecutableExt, kGccGenericCompileCommand,
41+
kGccExecutableLinkCommand);
42+
}
43+
44+
static TargetConfig DynamicLib() {
45+
return DefaultMingwConfig(kMingwDynamicLibExt, kGccGenericCompileCommand,
46+
kMingwDynamicLibLinkCommand);
47+
}
48+
49+
private:
50+
static TargetConfig DefaultMingwConfig(const std::string &target_ext,
51+
const std::string &compile_command,
52+
const std::string &link_command) {
53+
TargetConfig config;
54+
config.target_ext = target_ext;
55+
config.obj_ext = kGccObjExt;
56+
config.pch_header_ext = kGccPchHeaderExt;
57+
config.pch_compile_ext = kGccPchCompileExt;
58+
std::string prefix_include_dir = kGccPrefixIncludeDir;
59+
std::string prefix_lib_dir = kGccPrefixLibDir;
60+
config.pch_command = kGccGenericPchCompileCommand;
61+
config.compile_command = compile_command;
62+
config.link_command = link_command;
63+
return config;
64+
}
65+
};
66+
67+
class ExecutableTarget_mingw : public ExecutableTarget_gcc {
68+
public:
69+
ExecutableTarget_mingw(const std::string &name,
70+
const BaseToolchain &toolchain, const TargetEnv &env,
71+
const TargetConfig &config = MingwConfig::Executable())
72+
: ExecutableTarget_gcc(name, toolchain, env, config) {}
73+
};
74+
75+
typedef StaticTarget_gcc StaticTarget_mingw;
76+
77+
class DynamicTarget_mingw : public DynamicTarget_gcc {
78+
public:
79+
DynamicTarget_mingw(const std::string &name, const BaseToolchain &toolchain,
80+
const TargetEnv &env,
81+
const TargetConfig &config = MingwConfig::DynamicLib())
82+
: DynamicTarget_gcc(name, toolchain, env, config) {}
83+
};
84+
85+
} // namespace buildcc
86+
87+
#endif

buildcc/toolchains/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
set(TOOLCHAIN_SPECIALIZED_SRCS
22
include/toolchains/toolchain_gcc.h
33
include/toolchains/toolchain_msvc.h
4+
include/toolchains/toolchain_mingw.h
45
)
56

67
if(${BUILDCC_BUILD_AS_SINGLE_LIB})
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2021-2022 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+
#ifndef TOOLCHAINS_TOOLCHAIN_MINGW_H_
18+
#define TOOLCHAINS_TOOLCHAIN_MINGW_H_
19+
20+
#include "toolchain/toolchain.h"
21+
22+
namespace buildcc {
23+
24+
class Toolchain_mingw : public BaseToolchain {
25+
public:
26+
Toolchain_mingw()
27+
: Toolchain(ToolchainId::MinGW, "gcc", "as", "gcc", "g++", "ar", "ld") {}
28+
Toolchain_mingw(const Toolchain_mingw &) = delete;
29+
};
30+
31+
} // namespace buildcc
32+
33+
#endif

docs/source/arch/style_guide.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Google Style
1515

1616
``[snake_case_variable_name]_`` for private member variables
1717

18-
``k[PascalCaseVariableName]`` constexpr variables and enum / enum classes names
18+
``k[PascalCaseVariableName]`` constexpr variables and enum / enum classes names ONLY when used internally
19+
20+
``[PascakCaseVariableName]`` constexpr variables and enum / enum classes names when exposed to users
1921

2022
.. attention:: If you see any wrong usage in the project please raise an issue

docs/source/examples/mingw.rst

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,172 @@ MinGW
22
=======
33

44
Lowlevel MinGW Tests
5+
6+
7+
Executable
8+
-----------
9+
10+
.. code-block:: cpp
11+
:linenos:
12+
:emphasize-lines: 2,6
13+
14+
// MINGW specialized Toolchain
15+
Toolchain_mingw mingw;
16+
17+
// MINGW specialized targets
18+
// Creates `Simple.exe`
19+
ExecutableTarget_mingw exetarget("Simple", mingw, "");
20+
exetarget.GlobSources("src");
21+
exetarget.AddIncludeDir("include", true);
22+
exetarget.Build();
23+
24+
// Build
25+
tf::Executor executor;
26+
executor.run(exetarget.GetTaskflow());
27+
executor.wait_for_all();
28+
29+
StaticLib
30+
----------
31+
32+
.. code-block:: cpp
33+
:linenos:
34+
:emphasize-lines: 2,6,13
35+
36+
// MINGW specialized Toolchain
37+
Toolchain_mingw mingw;
38+
39+
// MINGW specialized targets
40+
// Creates `librandom.lib`
41+
StaticTarget_mingw statictarget("librandom", mingw, "");
42+
statictarget.AddSource("src/random.cpp");
43+
statictarget.AddIncludeDir("include", true);
44+
statictarget.Build();
45+
46+
// MINGW specialized targets
47+
// Creates `Simple.exe`
48+
ExecutableTarget_mingw exetarget("Simple", mingw, "");
49+
exetarget.AddSource("src/main.cpp");
50+
exetarget.AddIncludeDir("include", true);
51+
exetarget.AddLibDep(statictarget);
52+
exetarget.Build();
53+
54+
// Build
55+
tf::Executor executor;
56+
tf::Taskflow taskflow;
57+
58+
// Setup your dependencies explicitly
59+
// Here statictarget needs to be built before exetarget
60+
auto statictargetTask = taskflow.composed_of(statictarget.GetTaskflow());
61+
auto exetargetTask = taskflow.composed_of(exetarget.GetTaskflow());
62+
exetargetTask.succeed(statictargetTask);
63+
64+
executor.run(taskflow);
65+
executor.wait_for_all();
66+
67+
DynamicLib
68+
-----------
69+
70+
.. code-block:: cpp
71+
:linenos:
72+
:emphasize-lines: 2,6,13
73+
74+
// MINGW specialized Toolchain
75+
Toolchain_mingw mingw;
76+
77+
// MINGW specialized targets
78+
// Creates `librandom.lib` and `librandom.lib.dll`
79+
DynamicTarget_mingw dynamictarget("librandom", mingw, "");
80+
dynamictarget.AddSource("src/random.cpp");
81+
dynamictarget.AddIncludeDir("include", true);
82+
dynamictarget.Build();
83+
84+
// MINGW specialized target
85+
// Creates `Simple.exe` which uses the above dynamic library
86+
ExecutableTarget_mingw exetarget("Simple", mingw, "");
87+
exetarget.AddSource("src/main.cpp");
88+
exetarget.AddIncludeDir("include", true);
89+
exetarget.AddLibDep(dynamictarget);
90+
exetarget.Build();
91+
92+
// Build
93+
tf::Executor executor;
94+
tf::Taskflow taskflow;
95+
96+
// Setup your dependencies explicitly
97+
// Here dynamictarget needs to be built before exetarget
98+
auto dynamictargetTask = taskflow.composed_of(dynamictarget.GetTaskflow());
99+
auto exetargetTask = taskflow.composed_of(exetarget.GetTaskflow());
100+
exetargetTask.succeed(dynamictargetTask);
101+
102+
executor.run(taskflow);
103+
executor.wait_for_all();
104+
105+
// Now that both your targets are built, copy the dynamictarget DLL to the exetarget location
106+
// This is required for your exetarget to run properly
107+
if (exetarget.IsBuilt()) {
108+
fs::path copy_to_path =
109+
exetarget.GetTargetBuildDir() / dynamictarget.GetTargetPath().filename();
110+
fs::remove_all(copy_to_path);
111+
fs::copy(dynamictarget.GetTargetPath(), copy_to_path);
112+
}
113+
114+
115+
.. note:: Our ``ExecutableTarget_mingw`` depends on ``DynamicTarget_mingw`` and requires the ``librandom.dll`` file to be present in the same folder location as the executable when running.
116+
117+
PrecompileHeader
118+
-------------------
119+
120+
.. code-block:: cpp
121+
:linenos:
122+
:emphasize-lines: 2,4,7,24,25,26,39,40,41
123+
124+
int main() {
125+
Toolchain_mingw mingw;
126+
127+
ExecutableTarget_mingw g_cppflags("cppflags", mingw, "files");
128+
cppflags_build_cb(g_cppflags);
129+
130+
ExecutableTarget_mingw g_cflags("cflags", mingw, "files");
131+
cflags_build_cb(g_cflags);
132+
133+
tf::Executor executor;
134+
tf::Taskflow taskflow;
135+
136+
taskflow.composed_of(g_cppflags.GetTaskflow());
137+
taskflow.composed_of(g_cflags.GetTaskflow());
138+
executor.run(taskflow);
139+
executor.wait_for_all();
140+
}
141+
142+
static void cppflags_build_cb(BaseTarget &cppflags) {
143+
cppflags.AddSource("main.cpp", "src");
144+
cppflags.AddSource("random.cpp", "src");
145+
cppflags.AddIncludeDir("include", true);
146+
147+
cppflags.AddPch("pch/pch_cpp.h");
148+
cppflags.AddPch("pch/pch_c.h");
149+
cppflags.AddIncludeDir("pch", true);
150+
151+
cppflags.AddPreprocessorFlag("-DRANDOM=1");
152+
cppflags.AddCppCompileFlag("-Wall");
153+
cppflags.AddCppCompileFlag("-Werror");
154+
cppflags.AddLinkFlag("-lm");
155+
156+
cppflags.Build();
157+
}
158+
159+
static void cflags_build_cb(BaseTarget &cflags) {
160+
cflags.AddSource("main.c", "src");
161+
162+
cflags.AddPch("pch/pch_c.h");
163+
cflags.AddIncludeDir("pch", false);
164+
cflags.AddHeader("pch/pch_c.h");
165+
166+
cflags.AddPreprocessorFlag("-DRANDOM=1");
167+
cflags.AddCCompileFlag("-Wall");
168+
cflags.AddCCompileFlag("-Werror");
169+
cflags.AddLinkFlag("-lm");
170+
171+
cflags.Build();
172+
}
173+

example/README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,7 @@ Multi hosts but only one target compiler used
6262

6363
> NOTE, See the distinction between **HOST** and **TARGET**
6464
65-
## [host] MinGW GCC/GNU -> [target] gcc
66-
## [host] MSVC -> [target] gcc
67-
## [host] Linux GCC/GNU -> [target] gcc
65+
## [target] Gcc
6866

6967
- [x] Simple
7068
- Only 1 source file
@@ -84,7 +82,7 @@ Multi hosts but only one target compiler used
8482
- [ ] ClangFormat
8583
- [ ] Taskflow graph visualizer
8684

87-
## [host] MSVC -> [target] MSVC
85+
## [target] MSVC
8886

8987
> TODO, Understand how MSVC compilation using `cl.exe` occurs
9088
@@ -95,6 +93,12 @@ Multi hosts but only one target compiler used
9593
- [x] DynamicLib
9694
- MSVC DynamicLib + Executable
9795

96+
## [target] MinGW
97+
98+
- [x] Executable
99+
- [x] StaticLib
100+
- [x] DynamicLib
101+
98102
# Real world Tests (Hybrid)
99103

100104
Multi hosts and multi targets

example/mingw/DynamicLib/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Folder
2+
generated
3+
buildcc
4+
5+
# Files
6+
*.exe
7+
*.o
8+
*.bin

0 commit comments

Comments
 (0)