X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=blobdiff_plain;f=vg_build.h;h=fbfbf95062e56f5c744f36f58685abd4ecfb4895;hp=53de6c3edacc3cc3ac8b3415b5223c5dfbe54540;hb=HEAD;hpb=71cdc299d260abd83eec20748578805509d5468f diff --git a/vg_build.h b/vg_build.h index 53de6c3..b40ecd3 100644 --- a/vg_build.h +++ b/vg_build.h @@ -1,258 +1,548 @@ +/* zig cc scripting tools */ + #include #include #include +#include +#include +#include "vg_opt.h" #include "vg_log.h" +#include "vg_string.h" +#include "vg_build_font.h" + +/* we dont free dynamic vg_strs in this program. so, we dont care.. */ +const char *__asan_default_options() { return "detect_leaks=0"; } -struct compiler_info +struct vg_env { - char name[64], - file[512], - link[512], - library[512], - include[512], - build_dir[512], - executable[512]; - - enum optimization_profile + u32 optimization; + + bool fresh, + debug_asan; + + enum platform { - k_optimization_profile_debug, - k_optimization_profile_release + k_platform_anyplatform, + k_platform_windows, + k_platform_linux } - optimization_profile; + platform; - enum target_file + enum architecture { - k_target_file_game, - k_target_file_server + k_architecture_anyarch, + k_architecture_i386, + k_architecture_x86_64, } - target_file; - - enum compiler + arch; + + enum compiler { + k_compiler_blob, k_compiler_clang, - k_compiler_gcc, - k_compiler_mingw + k_compiler_zigcc } compiler; -} -static vg_compiler; - -void vg_build_syscall(const char *fmt, ...) + enum libc_version + { + k_libc_version_native, + k_libc_version_2_23, + } + libc; +}; + +struct vg_env vg_test_env = { + .arch = k_architecture_x86_64, + .compiler = k_compiler_clang, + .libc = k_libc_version_native, + .debug_asan = 1, + .fresh = 0, + .platform = k_platform_linux, + .optimization = 0 +}; + +struct vg_env vg_release_env = { + .arch = k_architecture_x86_64, + .compiler = k_compiler_zigcc, + .libc = k_libc_version_2_23, + .fresh = 1, + .optimization = 3, + .platform = k_platform_anyplatform, + .debug_asan = 0 +}; + +struct vg_project { - va_list args; - va_start( args, fmt ); - - char call[4096]; - vsnprintf( call, vg_list_size( call ), fmt, args ); + struct vg_env *env; + + vg_str include, /* -I */ + library, /* -L */ + link, /* -llibrary */ + sources, /* file.c obj.o */ + uid, /* env/project identifier */ + target, /* result object name */ + + /* generated */ + compiled_objects; /* space seperated paths to compiled objects */ + + enum obj_type { + k_obj_type_none, + k_obj_type_exe, + k_obj_type_obj, + k_obj_type_shared, + } + type; +}; - va_end( args ); +/* + * string tables + * -------------------------------------------------------------------------- */ - puts( call ); +static const char *platform_names[] = +{ + [k_platform_anyplatform] = "anyplatform", + [k_platform_windows] = "windows", + [k_platform_linux] = "linux" +}; - if( system(call) ) - exit(0); -} +static const char *architecture_names[] = +{ + [k_architecture_anyarch] = "anyarch", + [k_architecture_i386] = "i386", + [k_architecture_x86_64] = "x86_64" +}; -void vg_build_object( const char *file ) +static const char *compiler_names[] = { - strcat( vg_compiler.file, file ); -} + [k_compiler_blob] = "blob", + [k_compiler_clang] = "clang", + [k_compiler_zigcc] = "zig-cc" +}; -void vg_build_library_dir( const char *ldir ) +static const char *compiler_paths[] = { - strcat( vg_compiler.library, ldir ); -} + [k_compiler_blob] = NULL, + [k_compiler_clang] = "clang", + [k_compiler_zigcc] = "zig cc" +}; -void vg_build_link( const char *link ) +static const char *libc_names[] = { - strcat( vg_compiler.link, link ); -} + [k_libc_version_native] = "", + [k_libc_version_2_23] = ".2.23" +}; + +/* + * source specification + * -------------------------------------------------------------------------- */ -void vg_build_include( const char *inc ) +void vg_add_source( struct vg_project *proj, const char *source ) { - strcat( vg_compiler.include, inc ); + if( proj->type == k_obj_type_none ) + vg_fatal_error( "Cannot add source code without setting binary type\n" ); + + vg_strcat( &proj->sources, source ); + vg_strcat( &proj->sources, " " ); } -const char *vg_compiler_str(void) +void vg_include_dir( struct vg_project *proj, const char *dir ) { - return (const char *[]){ "clang", "gcc", "i686-w64-mingw32-gcc" } - [vg_compiler.compiler]; + if( proj->type == k_obj_type_none ) + vg_fatal_error( "Cannot add include dir without setting binary type\n" ); + + vg_strcat( &proj->include, dir ); + vg_strcat( &proj->include, " " ); } -void vg_build_start( const char *name, enum compiler compiler ) +void vg_library_dir( struct vg_project *proj, const char *dir ) { - vg_compiler.file[0] = '\0'; - vg_compiler.link[0] = '\0'; - vg_compiler.include[0] = '\0'; - vg_compiler.library[0] = '\0'; - vg_compiler.compiler = compiler; - - strcpy( vg_compiler.name, name ); - - snprintf( vg_compiler.build_dir, 512, - "bin/%s-%s", - name, - vg_compiler_str() ); - - vg_build_syscall( "mkdir -p %s", vg_compiler.build_dir ); - vg_build_include( "-I. -I./vg " ); - vg_build_library_dir( "-L. " ); + if( proj->type == k_obj_type_none ) + vg_fatal_error( "Cannot add library dir without setting binary type\n" ); + + vg_strcat( &proj->library, dir ); + vg_strcat( &proj->library, " " ); } -void vg_build_add_link_for_graphics(void) +void vg_link( struct vg_project *proj, const char *lib ) { - if( (vg_compiler.compiler == k_compiler_gcc) || - (vg_compiler.compiler == k_compiler_clang ) ) - { - vg_build_link( "-lSDL2 -lGL -lX11 -lXxf86vm -lXrandr -lXi -ldl " ); - } - else - { - vg_build_link( "-lmingw32 -lSDL2main -lSDL2 -lopengl32 -mwindows " ); - } + if( proj->type == k_obj_type_none ) + vg_fatal_error( "Cannot link library without setting binary type\n" ); - vg_build_object( "vg/dep/glad/glad.c " ); - vg_build_link( "-lm -pthread " ); + vg_strcat( &proj->link, lib ); } -void vg_build_add_link_for_game(void) +/* + * OS & file tools + * -------------------------------------------------------------------------- */ + +void vg_syscall( const char *fmt, ... ) { - if( (vg_compiler.compiler == k_compiler_gcc) || - (vg_compiler.compiler == k_compiler_clang ) ) - { - vg_build_link( "-lsteam_api " ); - } - else - { - vg_build_library_dir( "-L./vg/dep/sdl " ); - vg_build_link( "vg/dep/steam/steam_api.dll " ); - } + va_list args; + va_start( args, fmt ); - vg_build_include( "-I./vg/dep " ); - vg_build_library_dir( "-L./vg/dep/steam " ); + char call[4096]; + vsnprintf( call, sizeof(call), fmt, args ); + + va_end( args ); + vg_low( "%s\n", call ); + if( system(call) ) + exit(1); } -void vg_build_bin_dependency_file( const char *src ) +void vg_add_blob( struct vg_project *proj, const char *blob, const char *dest ) { - vg_build_syscall( "cp %s %s", src, vg_compiler.build_dir ); + vg_syscall( "cp %s bin/%s/%s", blob, proj->uid.buffer, dest ); } -void vg_build_symbolic_link( const char *folder, const char *bin_name ) +void vg_symlink( struct vg_project *proj, + const char *folder, const char *bin_name ) { char dest[512]; - snprintf( dest, 512, "%s/%s", vg_compiler.build_dir, bin_name ); - + snprintf( dest, 512, "bin/%s/%s", proj->uid.buffer, bin_name ); if( !access( dest, F_OK ) ) - vg_build_syscall( "unlink %s", dest ); + vg_syscall( "unlink %s", dest ); + vg_syscall( "ln -srf %s %s", folder, dest ); +} - vg_build_syscall( "ln -srf %s %s", folder, dest ); +void vg_tarball_project( struct vg_project *proj ) +{ + vg_syscall( "tar -chzvf dist/%s-%u.tar.gz bin/%s/", + proj->uid.buffer, time(NULL), proj->uid.buffer ); } -void vg_build_copy_graphics_dependencies(void) +/* + * The project configurator and compiler. + * -------------------------------------------------------------------------- */ + +void vg_project_new_target( struct vg_project *proj, const char *name, + enum obj_type type ) { - if( vg_compiler.compiler == k_compiler_mingw ) + proj->type = type; + + vg_strnull( &proj->include, NULL, -1 ); + vg_strnull( &proj->library, NULL, -1 ); + vg_strnull( &proj->link, NULL, -1 ); + vg_strnull( &proj->sources, NULL, -1 ); + vg_strnull( &proj->target, NULL, -1 ); + + /* + * Setup target with appropriate extension + */ + vg_strcat( &proj->target, name ); + + if( proj->env->platform == k_platform_windows ) { - vg_build_bin_dependency_file( "vg/dep/sdl/SDL2.dll" ); + if( type == k_obj_type_exe ) + vg_strcat( &proj->target, ".exe" ); + else if( type == k_obj_type_shared ) + vg_strcat( &proj->target, ".dll" ); + else if( type == k_obj_type_obj ) + vg_strcat( &proj->target, ".obj" ); } -} -void vg_build_copy_game_dependencies(void) -{ - vg_build_bin_dependency_file( - "vg/submodules/SDL_GameControllerDB/gamecontrollerdb.txt" ); - if( (vg_compiler.compiler == k_compiler_gcc) || - (vg_compiler.compiler == k_compiler_clang) ) + if( proj->env->platform == k_platform_linux ) { - vg_build_bin_dependency_file( "vg/dep/steam/libsteam_api.so" ); + if( type == k_obj_type_shared ) + vg_strcat( &proj->target, ".so" ); + else if( type == k_obj_type_obj ) + vg_strcat( &proj->target, ".o" ); } - else + + /* + * Add some regular includes / library dirs + */ + if( type != k_obj_type_none ) { - vg_build_bin_dependency_file( "vg/dep/steam/steam_api.dll" ); + vg_include_dir( proj, "-I." ); + vg_include_dir( proj, "-I./vg" ); + vg_library_dir( proj, "-L." ); + vg_library_dir( proj, "-L/usr/lib" ); } -} -void vg_build_mode_release(void) -{ - vg_compiler.optimization_profile = k_optimization_profile_release; + vg_info( " New target: %s\n", name ); } -void vg_build_mode_debug(void) +void vg_project_init( struct vg_project *proj, + struct vg_env *env, + const char *identifier ) { - vg_compiler.optimization_profile = k_optimization_profile_debug; + proj->env = env; + proj->type = k_obj_type_none; + + vg_strnull( &proj->uid, NULL, -1 ); + vg_strnull( &proj->compiled_objects, NULL, -1 ); + + /* check for problems in configuration */ + if( env->libc != k_libc_version_native ){ + if( env->compiler != k_compiler_zigcc ){ + vg_fatal_error( + "Cannot specify libc version using the '%s' compiler.\n", + compiler_names[ env->compiler ] ); + } + } + + if( env->compiler == k_compiler_clang ){ + if( env->platform != k_platform_linux ){ + vg_fatal_error( "Cannot compile for '%s' using the '%s' compiler;" ); + } + } + + vg_strcat( &proj->uid, identifier ); + vg_strcatch( &proj->uid, '-' ); + vg_strcat( &proj->uid, platform_names[ env->platform ] ); + vg_strcatch( &proj->uid, '-' ); + vg_strcat( &proj->uid, architecture_names[ env->arch ] ); + vg_strcatch( &proj->uid, '-' ); + vg_strcat( &proj->uid, compiler_names[ env->compiler ] ); + + if( proj->uid.i < 3 ) + vg_fatal_error( "failed to create project UID\n" ); + + vg_info( "project_init: %s (%s, %s, compiler: %s, opt:%u, fresh: %s)\n", + identifier, + platform_names[env->platform], + architecture_names[env->arch], + compiler_names[env->compiler], + env->optimization, + env->fresh? "yes":"no"); + + if( env->fresh ) + vg_syscall( "rm -rf bin/%s", proj->uid.buffer ); + vg_syscall( "mkdir -p bin/%s", proj->uid.buffer ); } -void vg_build(void) +void vg_compile_project( struct vg_project *proj ) { - char cmd[4096]; - cmd[0] = '\0'; + vg_str cmd; + vg_strnull( &cmd, NULL, -1 ); - /* Compiler */ - strcat( cmd, "ccache " ); - strcat( cmd, vg_compiler_str() ); - strcat( cmd, " -std=gnu99 -D_REENTRANT \\\n" ); + /* compiler specification */ + vg_strcat( &cmd, "ccache " ); + vg_strcat( &cmd, compiler_paths[ proj->env->compiler ] ); + vg_strcat( &cmd, " -std=gnu99 -D_REENTRANT \\\n" ); - /* Debugging information */ - if( vg_compiler.optimization_profile == k_optimization_profile_debug ) + if( proj->env->optimization ) { - strcat( cmd, " -O0 -ggdb3 -fno-omit-frame-pointer " ); + vg_strcat( &cmd, " -O" ); + vg_strcati32( &cmd, proj->env->optimization ); + vg_strcat( &cmd, " -flto \\\n" ); + } + else + { + /* add debugger / asan information */ + vg_strcat( &cmd, " -O0 -ggdb3 -fno-omit-frame-pointer " ); - if( (vg_compiler.compiler == k_compiler_gcc) || - (vg_compiler.compiler == k_compiler_clang ) ) + if( (proj->env->compiler == k_compiler_clang) && proj->env->debug_asan ) { - strcat( cmd, "-rdynamic -fsanitize=address " ); + vg_strcat( &cmd, " -rdynamic -fsanitize=address -fPIE " + "-fstack-protector-strong " ); } - strcat( cmd, "\\\n" ); + vg_strcat( &cmd, "\\\n" ); } - else + + /* want a lot of warnings but not useless ones */ + vg_strcat( &cmd, " -Wall -ferror-limit=8\\\n" + " -Wno-unused-function -Wno-unused-variable\\\n" + " -Wno-unused-command-line-argument -Wno-unused-but-set-variable\\\n" + ); + + if( proj->env->compiler != k_compiler_clang ) + vg_strcat( &cmd, " -Wno-format-truncation\\\n" ); + + /* include paths */ + vg_strcat( &cmd, " " ); + vg_strcat( &cmd, proj->include.buffer ); + vg_strcat( &cmd, "\\\n" ); + + /* library paths */ + vg_strcat( &cmd, " " ); + vg_strcat( &cmd, proj->library.buffer ); + vg_strcat( &cmd, "\\\n" ); + + /* sources */ + vg_strcat( &cmd, " " ); + + if( proj->type == k_obj_type_obj ) + vg_strcat( &cmd, "-c " ); + + if( proj->type == k_obj_type_shared ) + vg_strcat( &cmd, "-shared -fPIC " ); + + vg_strcat( &cmd, proj->sources.buffer ); + vg_strcat( &cmd, "\\\n" ); + + /* output */ + vg_strcat( &cmd, " -o bin/" ); + vg_strcat( &cmd, proj->uid.buffer ); + vg_strcat( &cmd, "/" ); + vg_strcat( &cmd, proj->target.buffer ); + vg_strcat( &cmd, "\\\n" ); + + /* link */ + vg_strcat( &cmd, " " ); + vg_strcat( &cmd, proj->link.buffer ); + vg_strcat( &cmd, "\\\n" ); + + if( proj->type == k_obj_type_exe ) { - strcat( cmd, " -O3 -DVG_RELEASE\\\n" ); + vg_strcat( &cmd, " -Wl,-rpath=./\\\n" ); } - /* Warnings */ - strcat( cmd, - " -Wall -ferror-limit=0\\\n" - " -Wno-unused-function -Wno-unused-variable\\\n" - " -Wno-unused-command-line-argument -Wno-unused-but-set-variable\\\n" - ); + /* target platform specification (zig-cc only) */ + if( proj->env->compiler == k_compiler_zigcc ){ + vg_strcat( &cmd, " -target " ); + vg_strcat( &cmd, architecture_names[proj->env->arch] ); + vg_strcat( &cmd, "-" ); + vg_strcat( &cmd, platform_names[proj->env->platform] ); + + if( proj->env->platform == k_platform_linux ){ + vg_strcat( &cmd, "-gnu" ); + vg_strcat( &cmd, libc_names[proj->env->libc] ); + } - /* Include */ - strcat( cmd, " " ); - strcat( cmd, vg_compiler.include ); - strcat( cmd, "\\\n" ); + if( proj->env->platform == k_platform_windows ) + { + /* we currently dont want pdb pretty much ever. goodbye! */ + + if( proj->type == k_obj_type_exe ) + { + vg_strcat( &cmd, " /pdb:/dev/null" ); + vg_strcat( &cmd, " /SUBSYSTEM:windows" ); + } + } + } + + vg_syscall( cmd.buffer ); - /* Library */ - strcat( cmd, " " ); - strcat( cmd, vg_compiler.library ); - strcat( cmd, "\\\n" ); + /* add to results */ + vg_strcat( &proj->compiled_objects, "bin/" ); + vg_strcat( &proj->compiled_objects, proj->uid.buffer ); + vg_strcat( &proj->compiled_objects, "/" ); + vg_strcat( &proj->compiled_objects, proj->target.buffer ); + vg_strcat( &proj->compiled_objects, " \\\n " ); +} - /* Targets */ - strcat( cmd, " " ); - strcat( cmd, vg_compiler.file ); - strcat( cmd, "\\\n" ); +/* + * Standard VG includes & libraries which we use for games/graphics + * -------------------------------------------------------------------------- */ + +struct vg_engine_config +{ + bool use_3d, legacy_support_vg_msg1, log_source_info, steam_api, + custom_game_settings, + custom_shaders; + i32 fixed_update_hz; +} +vg_engine_default_config = { + .use_3d = 1, + .fixed_update_hz = 60, + .legacy_support_vg_msg1 = 0, + .log_source_info = 1, + .steam_api = 0, + .custom_game_settings = 0, + .custom_shaders = 0 +}; + +void vg_add_engine( struct vg_project *proj, struct vg_engine_config *config ) +{ + /* building assets */ + vg_build_default_font(); + + if( !config ) config = &vg_engine_default_config; + vg_str config_string; + vg_strnull( &config_string, NULL, -1 ); + vg_strcat( &config_string, config->use_3d? "-DVG_3D \\\n": "-DVG_2D \\\n" ); + vg_strcat( &config_string, "-DVG_TIMESTEP_FIXED=\"(1.0/" ); + vg_strcati32( &config_string, config->fixed_update_hz ); + vg_strcat( &config_string, ".0)\" \\\n" ); + if( config->legacy_support_vg_msg1 ) + vg_strcat( &config_string, "-DVG_MSG_V1_SUPPORT \\\n" ); + if( config->log_source_info ) + vg_strcat( &config_string, "-DVG_LOG_SOURCE_INFO \\\n" ); + if( config->custom_game_settings ) + vg_strcat( &config_string, "-DVG_GAME_SETTINGS \\\n" ); + if( config->custom_shaders ) + vg_strcat( &config_string, "-DVG_CUSTOM_SHADERS \\\n" ); + + vg_strcat( &config_string, "\\\n" ); + + /* compile heavy dependencies seperately */ + struct vg_project dep_proj; + struct vg_env env = *proj->env; + env.optimization = 3; + env.debug_asan = 0; + + vg_project_init( &dep_proj, proj->env, "vg" ); + + /* external dependencies */ + vg_project_new_target( &dep_proj, "vg_deps", k_obj_type_obj ); + vg_add_source( &dep_proj, "vg/vg_depencies.c" ); + vg_compile_project( &dep_proj ); + + /* glad */ + vg_project_new_target( &dep_proj, "vg_glad", k_obj_type_obj ); + vg_add_source( &dep_proj, "vg/dep/glad/glad.c" ); + vg_include_dir( &dep_proj, "-I./vg/dep " ); + vg_compile_project( &dep_proj ); + + /* core engine */ + vg_project_new_target( &dep_proj, "vg_engine_core", k_obj_type_obj ); + vg_add_source( &dep_proj, config_string.buffer ); + vg_add_source( &dep_proj, "vg/vg_engine.c" ); + vg_include_dir( &dep_proj, "-I./vg/dep " ); + vg_compile_project( &dep_proj ); + + /* steamworks */ + if( config->steam_api ) + { + vg_project_new_target( &dep_proj, "vg_steam", k_obj_type_obj ); + vg_add_source( &dep_proj, "vg/vg_steam.c" ); + vg_compile_project( &dep_proj ); - /* Output */ - strcat( cmd, " -o " ); - vg_compiler.executable[0] = '\0'; - strcat( vg_compiler.executable, vg_compiler.build_dir ); - strcat( vg_compiler.executable, "/" ); - strcat( vg_compiler.executable, vg_compiler.name ); + if( proj->env->platform == k_platform_linux ) + { + vg_add_blob( proj, "vg/dep/steam/libsteam_api.so", "" ); + vg_link( proj, "-lsteam_api " ); + } + else if( proj->env->platform == k_platform_windows ) + { + vg_add_blob( proj, "vg/dep/steam/steam_api64.dll", "" ); + vg_link( proj, "vg/dep/steam/steam_api64.dll " ); + } - if( vg_compiler.compiler == k_compiler_mingw ) - strcat( vg_compiler.executable, ".exe" ); + vg_library_dir( proj, "-L./vg/dep/steam " ); + vg_include_dir( proj, "-I./vg/dep " ); + } - strcat( cmd, vg_compiler.executable ); - strcat( cmd, "\\\n" ); + /* precipitate to the client project */ - /* Link */ - strcat( cmd, " " ); - strcat( cmd, vg_compiler.link ); - strcat( cmd, "\\\n" ); + vg_link( proj, "-lm " ); + if( proj->env->platform == k_platform_linux ) + { + vg_link( proj, "-lSDL2 -lGL -lX11 -lXxf86vm " + "-lXrandr -lXi -ldl -pthread " ); + } + else if( proj->env->platform == k_platform_windows ) + { + vg_link( proj, "-lSDL2main -lSDL2 -lopengl32 \\\n" ); + vg_link( proj, "vg/dep/sdl/SDL2.dll " ); + vg_add_blob( proj, "vg/dep/sdl/SDL2.dll ", "" ); + vg_library_dir( proj, "-L./vg/dep/sdl " ); + } - strcat( cmd, " -Wl,-rpath=./" ); + vg_add_source( proj, config_string.buffer ); + vg_add_source( proj, dep_proj.compiled_objects.buffer ); + vg_add_source( proj, "\\\n" ); + vg_include_dir( proj, "-I./vg/dep " ); + vg_link( proj, "-lm " ); +} - vg_build_syscall( cmd ); +void vg_add_controller_database( struct vg_project *proj ) +{ + vg_add_blob( proj, + "vg/submodules/SDL_GameControllerDB/gamecontrollerdb.txt", "" ); }