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