a30fe17f9b73e57852db3c29bd7478a7cf80c6f9
[vg.git] / vg_build.h
1 /* zig cc scripting tools */
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <time.h>
7
8 #include "vg.h"
9 #include "vg_opt.h"
10 #include "vg_log.h"
11
12 /* we dont free dynamic vg_strs in this program. so, we dont care.. */
13 const char *__asan_default_options() { return "detect_leaks=0"; }
14
15 struct {
16 vg_str include,
17 library,
18 link,
19 sources,
20 dest,
21 project_name;
22
23 u32 optimization,
24 warnings;
25 bool fresh,
26 debug_asan,
27 build_times;
28
29 enum platform {
30 k_platform_anyplatform,
31 k_platform_windows,
32 k_platform_linux
33 }
34 platform;
35
36 enum architecture {
37 k_architecture_anyarch,
38 k_architecture_i386,
39 k_architecture_x86_64,
40 }
41 arch;
42
43 enum compiler {
44 k_compiler_blob,
45 k_compiler_clang,
46 k_compiler_zigcc
47 }
48 compiler;
49
50 enum libc_version {
51 k_libc_version_native,
52 k_libc_version_2_23,
53 }
54 libc;
55 }
56 static vg_build = { .debug_asan = 1 };
57
58 /*
59 * string tables
60 * -------------------------------------------------------------------------- */
61
62 static const char *platform_names[] = {
63 [k_platform_anyplatform] = "anyplatform",
64 [k_platform_windows] = "windows",
65 [k_platform_linux] = "linux"
66 };
67
68 static const char *architecture_names[] = {
69 [k_architecture_anyarch] = "anyarch",
70 [k_architecture_i386] = "i386",
71 [k_architecture_x86_64] = "x86_64"
72 };
73
74 static const char *compiler_names[] = {
75 [k_compiler_blob] = "blob",
76 [k_compiler_clang] = "clang",
77 [k_compiler_zigcc] = "zig-cc"
78 };
79
80 static const char *compiler_paths[] = {
81 [k_compiler_blob] = NULL,
82 [k_compiler_clang] = "clang",
83 [k_compiler_zigcc] = "zig cc"
84 };
85
86 static const char *libc_names[] = {
87 [k_libc_version_native] = "",
88 [k_libc_version_2_23] = ".2.23"
89 };
90
91 /*
92 * source specification
93 * -------------------------------------------------------------------------- */
94
95 void vg_add_source( const char *source ){
96 vg_strcat( &vg_build.sources, source );
97 vg_strcat( &vg_build.sources, " " );
98 }
99
100 void vg_include_dir( const char *dir ){
101 vg_strcat( &vg_build.include, dir );
102 vg_strcat( &vg_build.include, " " );
103 }
104
105 void vg_library_dir( const char *dir ){
106 vg_strcat( &vg_build.library, dir );
107 vg_strcat( &vg_build.library, " " );
108 }
109
110 void vg_link( const char *lib ){
111 vg_strcat( &vg_build.link, lib );
112 }
113
114 /*
115 * OS & file tools
116 * -------------------------------------------------------------------------- */
117
118 void vg_syscall( const char *fmt, ... ){
119 va_list args;
120 va_start( args, fmt );
121
122 char call[4096];
123 vsnprintf( call, sizeof(call), fmt, args );
124
125 va_end( args );
126 vg_low( "%s\n", call );
127 if( system(call) )
128 exit(1);
129 }
130
131 void vg_add_blob( const char *blob, const char *dest ){
132 vg_syscall( "cp %s bin/%s/%s", blob, vg_build.project_name.buffer, dest );
133 }
134
135 void vg_symlink( const char *folder, const char *bin_name ){
136 char dest[512];
137 snprintf( dest, 512, "bin/%s/%s", vg_build.project_name.buffer, bin_name );
138 if( !access( dest, F_OK ) )
139 vg_syscall( "unlink %s", dest );
140 vg_syscall( "ln -srf %s %s", folder, dest );
141 }
142
143 void vg_tarball_last_project(void){
144 vg_syscall( "tar -chzvf dist/%s-%u.tar.gz bin/%s/",
145 vg_build.project_name.buffer, time(NULL),
146 vg_build.project_name.buffer );
147 }
148
149
150 /*
151 * Standard VG includes & libraries which we use for games/graphics
152 * -------------------------------------------------------------------------- */
153
154 void vg_add_graphics(void){
155 vg_add_source( "vg/dep/glad/glad.c" );
156
157 if( vg_build.platform == k_platform_windows )
158 vg_add_blob( "vg/dep/sdl/SDL2.dll", "" );
159
160 vg_link( "-lm " );
161
162 if( vg_build.platform == k_platform_linux )
163 vg_link( "-lSDL2 -lGL -lX11 -lXxf86vm -lXrandr -lXi -ldl -pthread " );
164 else
165 vg_link( "-lmingw32 -lSDL2main -lSDL2 -lopengl32 \\\n" );
166 }
167
168 void vg_add_game_stuff(void){
169 vg_add_blob( "vg/submodules/SDL_GameControllerDB/gamecontrollerdb.txt", "" );
170
171 if( vg_build.platform == k_platform_linux ){
172 vg_add_blob( "vg/dep/steam/libsteam_api.so", "" );
173 vg_link( "-lsteam_api " );
174 }
175 else if( vg_build.platform == k_platform_windows ){
176 vg_add_blob( "vg/dep/steam/steam_api64.dll", "" );
177 vg_link( "vg/dep/steam/steam_api64.dll " );
178 vg_link( "vg/dep/sdl/SDL2.dll " );
179 vg_library_dir( "-L./vg/dep/sdl " );
180 }
181
182 vg_include_dir( "-I./vg/dep " );
183 vg_library_dir( "-L./vg/dep/steam " );
184 }
185
186 /*
187 * The project configurator and compiler.
188 * -------------------------------------------------------------------------- */
189
190 void vg_build_new( const char *name ){
191 vg_strnull( &vg_build.include, NULL, -1 );
192 vg_strnull( &vg_build.library, NULL, -1 );
193 vg_strnull( &vg_build.link, NULL, -1 );
194 vg_strnull( &vg_build.sources, NULL, -1 );
195 vg_strnull( &vg_build.dest, NULL, -1 );
196 vg_strnull( &vg_build.project_name, NULL, -1 );
197
198 /* check for problems in configuration */
199 if( vg_build.libc != k_libc_version_native ){
200 if( vg_build.compiler != k_compiler_zigcc ){
201 vg_build.warnings ++;
202 vg_warn( "Cannot specify libc version using the '%s' compiler.\n",
203 compiler_names[ vg_build.compiler ] );
204 }
205 }
206
207 if( vg_build.compiler == k_compiler_clang ){
208 if( vg_build.platform != k_platform_linux ){
209 vg_build.warnings ++;
210 vg_warn( "Cannot compile for '%s' using the '%s' compiler;" );
211 }
212 }
213
214 vg_str *proj = &vg_build.project_name;
215
216 vg_strcat( proj, name );
217 vg_strcatch( proj, '-' );
218 vg_strcat( proj, platform_names[ vg_build.platform ] );
219 vg_strcatch( proj, '-' );
220 vg_strcat( proj, architecture_names[ vg_build.arch ] );
221 vg_strcatch( proj, '-' );
222 vg_strcat( proj, compiler_names[ vg_build.compiler ] );
223
224 vg_info( "project: %s (%s, %s, compiler: %s, opt:%u, fresh: %s)\n",
225 name,
226 platform_names[vg_build.platform],
227 architecture_names[vg_build.arch],
228 compiler_names[vg_build.compiler],
229 vg_build.optimization,
230 vg_build.fresh? "yes":"no");
231
232 if( proj->i < 3 )
233 vg_fatal_error( "failed to create output directory\n" );
234
235 if( vg_build.fresh )
236 vg_syscall( "rm -rf bin/%s", proj->buffer );
237 vg_syscall( "mkdir -p bin/%s", proj->buffer );
238
239 vg_include_dir( "-I." );
240 vg_include_dir( "-I./vg" );
241 vg_library_dir( "-L." );
242 vg_library_dir( "-L/usr/lib" );
243 }
244
245 void vg_compile( const char *name ){
246 vg_str cmd;
247 vg_strnull( &cmd, NULL, -1 );
248
249 /* compiler specification */
250 vg_strcat( &cmd, "ccache " );
251 vg_strcat( &cmd, compiler_paths[ vg_build.compiler ] );
252 vg_strcat( &cmd, " -std=gnu99 -D_REENTRANT \\\n" );
253
254 if( vg_build.optimization ){
255 vg_strcat( &cmd, " -O" );
256 vg_strcati32( &cmd, vg_build.optimization );
257 vg_strcat( &cmd, " -DVG_RELEASE\\\n" );
258 }
259 else {
260 /* add debugger / asan information */
261 vg_strcat( &cmd, " -O0 -ggdb3 -fno-omit-frame-pointer " );
262
263 if( (vg_build.compiler == k_compiler_clang) && vg_build.debug_asan ){
264 vg_strcat( &cmd, " -rdynamic -fsanitize=address -fPIE "
265 "-fstack-protector-strong " );
266 }
267
268 vg_strcat( &cmd, "\\\n" );
269 }
270
271 /* want a lot of warnings but not useless ones */
272 vg_strcat( &cmd, " -Wall -ferror-limit=8\\\n"
273 " -Wno-unused-function -Wno-unused-variable -Wno-format-truncation\\\n"
274 " -Wno-unused-command-line-argument -Wno-unused-but-set-variable\\\n"
275 );
276
277 /* include paths */
278 vg_strcat( &cmd, " " );
279 vg_strcat( &cmd, vg_build.include.buffer );
280 vg_strcat( &cmd, "\\\n" );
281
282 /* library paths */
283 vg_strcat( &cmd, " " );
284 vg_strcat( &cmd, vg_build.library.buffer );
285 vg_strcat( &cmd, "\\\n" );
286
287 /* sources */
288 vg_strcat( &cmd, " " );
289 vg_strcat( &cmd, vg_build.sources.buffer );
290 vg_strcat( &cmd, "\\\n" );
291
292 /* output */
293 vg_strcat( &cmd, " -o bin/" );
294 vg_strcat( &cmd, vg_build.project_name.buffer );
295 vg_strcat( &cmd, "/" );
296 vg_strcat( &cmd, name );
297 if( vg_build.platform == k_platform_windows )
298 vg_strcat( &cmd, ".exe" );
299 vg_strcat( &cmd, "\\\n" );
300
301 /* link */
302 vg_strcat( &cmd, " " );
303 vg_strcat( &cmd, vg_build.link.buffer );
304 vg_strcat( &cmd, "\\\n" );
305
306 /* dont remember what this does */
307 vg_strcat( &cmd, " -Wl,-rpath=./\\\n" );
308
309 /* target platform specification (zig-cc only) */
310 if( vg_build.compiler == k_compiler_zigcc ){
311 vg_strcat( &cmd, " -target " );
312 vg_strcat( &cmd, architecture_names[vg_build.arch] );
313 vg_strcat( &cmd, "-" );
314 vg_strcat( &cmd, platform_names[vg_build.platform] );
315
316 if( vg_build.platform == k_platform_linux ){
317 vg_strcat( &cmd, "-gnu" );
318 vg_strcat( &cmd, libc_names[vg_build.libc] );
319 }
320
321 if( vg_build.platform == k_platform_windows ){
322 /* we currently dont want pdb pretty much ever. goodbye! */
323 vg_strcat( &cmd, " /SUBSYSTEM:windows /pdb:/dev/null" );
324 }
325 }
326
327 vg_syscall( cmd.buffer );
328 }