X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=blobdiff_plain;f=vg_build.h;h=fbfbf95062e56f5c744f36f58685abd4ecfb4895;hp=965f14cac3941c73e687985360410d581b5008a3;hb=HEAD;hpb=9578dfc2859abc101f78c02c271aae44b351abca diff --git a/vg_build.h b/vg_build.h index 965f14c..b40ecd3 100644 --- a/vg_build.h +++ b/vg_build.h @@ -4,83 +4,132 @@ #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 { - vg_str include, - library, - link, - sources, - dest, - project_name; +struct vg_env +{ + u32 optimization; - u32 optimization, - warnings; bool fresh, debug_asan; - enum platform { + enum platform + { k_platform_anyplatform, k_platform_windows, k_platform_linux } platform; - enum architecture { + enum architecture + { k_architecture_anyarch, k_architecture_i386, k_architecture_x86_64, } arch; - enum compiler { + enum compiler + { k_compiler_blob, k_compiler_clang, k_compiler_zigcc } compiler; - enum libc_version { + enum libc_version + { k_libc_version_native, k_libc_version_2_23, } libc; -} -static vg_build = { .debug_asan = 1 }; +}; + +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 +{ + 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; +}; /* * string tables * -------------------------------------------------------------------------- */ -static const char *platform_names[] = { +static const char *platform_names[] = +{ [k_platform_anyplatform] = "anyplatform", [k_platform_windows] = "windows", [k_platform_linux] = "linux" }; -static const char *architecture_names[] = { +static const char *architecture_names[] = +{ [k_architecture_anyarch] = "anyarch", [k_architecture_i386] = "i386", [k_architecture_x86_64] = "x86_64" }; -static const char *compiler_names[] = { +static const char *compiler_names[] = +{ [k_compiler_blob] = "blob", [k_compiler_clang] = "clang", [k_compiler_zigcc] = "zig-cc" }; -static const char *compiler_paths[] = { +static const char *compiler_paths[] = +{ [k_compiler_blob] = NULL, [k_compiler_clang] = "clang", [k_compiler_zigcc] = "zig cc" }; -static const char *libc_names[] = { +static const char *libc_names[] = +{ [k_libc_version_native] = "", [k_libc_version_2_23] = ".2.23" }; @@ -89,30 +138,47 @@ static const char *libc_names[] = { * source specification * -------------------------------------------------------------------------- */ -void vg_add_source( const char *source ){ - vg_strcat( &vg_build.sources, source ); - vg_strcat( &vg_build.sources, " " ); +void vg_add_source( struct vg_project *proj, const char *source ) +{ + 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, " " ); } -void vg_include_dir( const char *dir ){ - vg_strcat( &vg_build.include, dir ); - vg_strcat( &vg_build.include, " " ); +void vg_include_dir( struct vg_project *proj, const char *dir ) +{ + 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_library_dir( const char *dir ){ - vg_strcat( &vg_build.library, dir ); - vg_strcat( &vg_build.library, " " ); +void vg_library_dir( struct vg_project *proj, const char *dir ) +{ + 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_link( const char *lib ){ - vg_strcat( &vg_build.link, lib ); +void vg_link( struct vg_project *proj, const char *lib ) +{ + if( proj->type == k_obj_type_none ) + vg_fatal_error( "Cannot link library without setting binary type\n" ); + + vg_strcat( &proj->link, lib ); } /* * OS & file tools * -------------------------------------------------------------------------- */ -void vg_syscall( const char *fmt, ... ){ +void vg_syscall( const char *fmt, ... ) +{ va_list args; va_start( args, fmt ); @@ -125,139 +191,152 @@ void vg_syscall( const char *fmt, ... ){ exit(1); } -void vg_add_blob( const char *blob, const char *dest ){ - vg_syscall( "cp %s bin/%s/%s", blob, vg_build.project_name.buffer, dest ); +void vg_add_blob( struct vg_project *proj, const char *blob, const char *dest ) +{ + vg_syscall( "cp %s bin/%s/%s", blob, proj->uid.buffer, dest ); } -void vg_symlink( 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, "bin/%s/%s", vg_build.project_name.buffer, bin_name ); + snprintf( dest, 512, "bin/%s/%s", proj->uid.buffer, bin_name ); if( !access( dest, F_OK ) ) vg_syscall( "unlink %s", dest ); vg_syscall( "ln -srf %s %s", folder, dest ); } -void vg_tarball_last_project(void){ +void vg_tarball_project( struct vg_project *proj ) +{ vg_syscall( "tar -chzvf dist/%s-%u.tar.gz bin/%s/", - vg_build.project_name.buffer, time(NULL), - vg_build.project_name.buffer ); + proj->uid.buffer, time(NULL), proj->uid.buffer ); } - /* - * Standard VG includes & libraries which we use for games/graphics + * The project configurator and compiler. * -------------------------------------------------------------------------- */ -void vg_add_graphics(void){ - vg_add_source( "vg/dep/glad/glad.c" ); - - if( vg_build.platform == k_platform_windows ) - vg_add_blob( "vg/dep/sdl/SDL2.dll", "" ); - - vg_link( "-lm " ); - - if( vg_build.platform == k_platform_linux ) - vg_link( "-lSDL2 -lGL -lX11 -lXxf86vm -lXrandr -lXi -ldl -pthread " ); - else - vg_link( "-lmingw32 -lSDL2main -lSDL2 -lopengl32 \\\n" ); -} +void vg_project_new_target( struct vg_project *proj, const char *name, + enum obj_type type ) +{ + 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 ) + { + 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_add_game_stuff(void){ - vg_add_blob( "vg/submodules/SDL_GameControllerDB/gamecontrollerdb.txt", "" ); - if( vg_build.platform == k_platform_linux ){ - vg_add_blob( "vg/dep/steam/libsteam_api.so", "" ); - vg_link( "-lsteam_api " ); + if( proj->env->platform == k_platform_linux ) + { + if( type == k_obj_type_shared ) + vg_strcat( &proj->target, ".so" ); + else if( type == k_obj_type_obj ) + vg_strcat( &proj->target, ".o" ); } - else if( vg_build.platform == k_platform_windows ){ - vg_add_blob( "vg/dep/steam/steam_api64.dll", "" ); - vg_link( "vg/dep/steam/steam_api64.dll " ); - vg_link( "vg/dep/sdl/SDL2.dll " ); - vg_library_dir( "-L./vg/dep/sdl " ); + + /* + * Add some regular includes / library dirs + */ + if( type != k_obj_type_none ) + { + vg_include_dir( proj, "-I." ); + vg_include_dir( proj, "-I./vg" ); + vg_library_dir( proj, "-L." ); + vg_library_dir( proj, "-L/usr/lib" ); } - vg_include_dir( "-I./vg/dep " ); - vg_library_dir( "-L./vg/dep/steam " ); + vg_info( " New target: %s\n", name ); } -/* - * The project configurator and compiler. - * -------------------------------------------------------------------------- */ +void vg_project_init( struct vg_project *proj, + struct vg_env *env, + const char *identifier ) +{ + proj->env = env; + proj->type = k_obj_type_none; -void vg_build_new( const char *name ){ - vg_strnull( &vg_build.include, NULL, -1 ); - vg_strnull( &vg_build.library, NULL, -1 ); - vg_strnull( &vg_build.link, NULL, -1 ); - vg_strnull( &vg_build.sources, NULL, -1 ); - vg_strnull( &vg_build.dest, NULL, -1 ); - vg_strnull( &vg_build.project_name, NULL, -1 ); + vg_strnull( &proj->uid, NULL, -1 ); + vg_strnull( &proj->compiled_objects, NULL, -1 ); /* check for problems in configuration */ - if( vg_build.libc != k_libc_version_native ){ - if( vg_build.compiler != k_compiler_zigcc ){ - vg_build.warnings ++; - vg_warn( "Cannot specify libc version using the '%s' compiler.\n", - compiler_names[ vg_build.compiler ] ); + 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( vg_build.compiler == k_compiler_clang ){ - if( vg_build.platform != k_platform_linux ){ - vg_build.warnings ++; - vg_warn( "Cannot compile for '%s' using the '%s' 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_str *proj = &vg_build.project_name; - - vg_strcat( proj, name ); - vg_strcatch( proj, '-' ); - vg_strcat( proj, platform_names[ vg_build.platform ] ); - vg_strcatch( proj, '-' ); - vg_strcat( proj, architecture_names[ vg_build.arch ] ); - vg_strcatch( proj, '-' ); - vg_strcat( proj, compiler_names[ vg_build.compiler ] ); - - vg_info( "project: %s (%s, %s, compiler: %s, opt:%u, fresh: %s)\n", - name, - platform_names[vg_build.platform], - architecture_names[vg_build.arch], - compiler_names[vg_build.compiler], - vg_build.optimization, - vg_build.fresh? "yes":"no"); - - if( proj->i < 3 ) - vg_fatal_error( "failed to create output directory\n" ); - - if( vg_build.fresh ) - vg_syscall( "rm -rf bin/%s", proj->buffer ); - vg_syscall( "mkdir -p bin/%s", proj->buffer ); - - vg_include_dir( "-I." ); - vg_include_dir( "-I./vg" ); - vg_library_dir( "-L." ); - vg_library_dir( "-L/usr/lib" ); + 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_compile( const char *name ){ +void vg_compile_project( struct vg_project *proj ) +{ vg_str cmd; vg_strnull( &cmd, NULL, -1 ); /* compiler specification */ vg_strcat( &cmd, "ccache " ); - vg_strcat( &cmd, compiler_paths[ vg_build.compiler ] ); + vg_strcat( &cmd, compiler_paths[ proj->env->compiler ] ); vg_strcat( &cmd, " -std=gnu99 -D_REENTRANT \\\n" ); - if( vg_build.optimization ){ + if( proj->env->optimization ) + { vg_strcat( &cmd, " -O" ); - vg_strcati32( &cmd, vg_build.optimization ); - vg_strcat( &cmd, " -DVG_RELEASE\\\n" ); + vg_strcati32( &cmd, proj->env->optimization ); + vg_strcat( &cmd, " -flto \\\n" ); } - else { + else + { /* add debugger / asan information */ vg_strcat( &cmd, " -O0 -ggdb3 -fno-omit-frame-pointer " ); - if( (vg_build.compiler == k_compiler_clang) && vg_build.debug_asan ){ + if( (proj->env->compiler == k_compiler_clang) && proj->env->debug_asan ) + { vg_strcat( &cmd, " -rdynamic -fsanitize=address -fPIE " "-fstack-protector-strong " ); } @@ -267,59 +346,203 @@ void vg_compile( const char *name ){ /* want a lot of warnings but not useless ones */ vg_strcat( &cmd, " -Wall -ferror-limit=8\\\n" - " -Wno-unused-function -Wno-unused-variable -Wno-format-truncation\\\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, vg_build.include.buffer ); + vg_strcat( &cmd, proj->include.buffer ); vg_strcat( &cmd, "\\\n" ); /* library paths */ vg_strcat( &cmd, " " ); - vg_strcat( &cmd, vg_build.library.buffer ); + vg_strcat( &cmd, proj->library.buffer ); vg_strcat( &cmd, "\\\n" ); /* sources */ vg_strcat( &cmd, " " ); - vg_strcat( &cmd, vg_build.sources.buffer ); + + 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, vg_build.project_name.buffer ); + vg_strcat( &cmd, proj->uid.buffer ); vg_strcat( &cmd, "/" ); - vg_strcat( &cmd, name ); - if( vg_build.platform == k_platform_windows ) - vg_strcat( &cmd, ".exe" ); + vg_strcat( &cmd, proj->target.buffer ); vg_strcat( &cmd, "\\\n" ); /* link */ vg_strcat( &cmd, " " ); - vg_strcat( &cmd, vg_build.link.buffer ); + vg_strcat( &cmd, proj->link.buffer ); vg_strcat( &cmd, "\\\n" ); - /* dont remember what this does */ - vg_strcat( &cmd, " -Wl,-rpath=./\\\n" ); + if( proj->type == k_obj_type_exe ) + { + vg_strcat( &cmd, " -Wl,-rpath=./\\\n" ); + } /* target platform specification (zig-cc only) */ - if( vg_build.compiler == k_compiler_zigcc ){ + if( proj->env->compiler == k_compiler_zigcc ){ vg_strcat( &cmd, " -target " ); - vg_strcat( &cmd, architecture_names[vg_build.arch] ); + vg_strcat( &cmd, architecture_names[proj->env->arch] ); vg_strcat( &cmd, "-" ); - vg_strcat( &cmd, platform_names[vg_build.platform] ); + vg_strcat( &cmd, platform_names[proj->env->platform] ); - if( vg_build.platform == k_platform_linux ){ + if( proj->env->platform == k_platform_linux ){ vg_strcat( &cmd, "-gnu" ); - vg_strcat( &cmd, libc_names[vg_build.libc] ); + vg_strcat( &cmd, libc_names[proj->env->libc] ); } - if( vg_build.platform == k_platform_windows ){ + if( proj->env->platform == k_platform_windows ) + { /* we currently dont want pdb pretty much ever. goodbye! */ - vg_strcat( &cmd, " /SUBSYSTEM:windows /pdb:/dev/null" ); + + if( proj->type == k_obj_type_exe ) + { + vg_strcat( &cmd, " /pdb:/dev/null" ); + vg_strcat( &cmd, " /SUBSYSTEM:windows" ); + } } } vg_syscall( cmd.buffer ); + + /* 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 " ); +} + +/* + * 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 ); + + 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 " ); + } + + vg_library_dir( proj, "-L./vg/dep/steam " ); + vg_include_dir( proj, "-I./vg/dep " ); + } + + /* precipitate to the client project */ + + 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 " ); + } + + 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 " ); +} + +void vg_add_controller_database( struct vg_project *proj ) +{ + vg_add_blob( proj, + "vg/submodules/SDL_GameControllerDB/gamecontrollerdb.txt", "" ); }