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..9a1d861 100644 --- a/vg_build.h +++ b/vg_build.h @@ -1,258 +1,538 @@ #include #include #include +#include +#include +#include "vg_opt.h" #include "vg_log.h" +#include "vg_string.h" +#include "vg_build_font.h" -struct compiler_info +/* we dont free dynamic vg_strs in this program. so, we dont care.. */ +const char *__asan_default_options() { return "detect_leaks=0"; } + +struct vg_project +{ + vg_str uid, bin_folder; +}; + +struct vg_compiler_env { - char name[64], - file[512], - link[512], - library[512], - include[512], - build_dir[512], - executable[512]; - - enum optimization_profile + u32 optimization; + bool 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; + + enum libc_version + { + k_libc_version_native, + k_libc_version_2_23, + } + libc; } +vg_test_env = +{ + .optimization = 0, + .debug_asan = 1, + .platform = k_platform_linux, + .arch = k_architecture_x86_64, + .compiler = k_compiler_clang, + .libc = k_libc_version_native +}, +vg_release_env = +{ + .optimization = 3, + .debug_asan = 0, + .platform = k_platform_anyplatform, + .arch = k_architecture_x86_64, + .compiler = k_compiler_zigcc, + .libc = k_libc_version_2_23 +}; + +struct vg_compiler_conf +{ + vg_str include, + library, + link, + defines; +}; + +enum obj_type +{ + k_obj_type_none, + k_obj_type_exe, + k_obj_type_obj, + k_obj_type_shared, +}; + +/* + * string tables + * -------------------------------------------------------------------------- */ -static vg_compiler; +static const char *platform_names[] = +{ + [k_platform_anyplatform] = "anyplatform", + [k_platform_windows] = "windows", + [k_platform_linux] = "linux", +}; + +static const char *architecture_names[] = +{ + [k_architecture_anyarch] = "anyarch", + [k_architecture_i386] = "i386", + [k_architecture_x86_64] = "x86_64", +}; + +static const char *compiler_names[] = +{ + [k_compiler_blob] = "blob", + [k_compiler_clang] = "clang", + [k_compiler_zigcc] = "zig-cc", +}; + +static const char *libc_names[] = +{ + [k_libc_version_native] = "", + [k_libc_version_2_23] = ".2.23" +}; -void vg_build_syscall(const char *fmt, ...) +/* + * OS & file tools + * -------------------------------------------------------------------------- */ + +void vg_syscall( const char *fmt, ... ) { va_list args; va_start( args, fmt ); char call[4096]; - vsnprintf( call, vg_list_size( call ), fmt, args ); + vsnprintf( call, sizeof(call), fmt, args ); va_end( args ); - - puts( call ); - + vg_low( "%s\n", call ); if( system(call) ) - exit(0); + exit(1); } -void vg_build_object( const char *file ) +void vg_add_blob( struct vg_project *proj, const char *blob, const char *dest ) { - strcat( vg_compiler.file, file ); + vg_syscall( "cp %s %s/%s", blob, proj->bin_folder.buffer, dest ); } -void vg_build_library_dir( const char *ldir ) +void vg_symlink( struct vg_project *proj, + const char *folder, const char *bin_name ) { - strcat( vg_compiler.library, ldir ); + char dest[512]; + snprintf( dest, 512, "%s/%s", proj->bin_folder.buffer, bin_name ); + if( !access( dest, F_OK ) ) + vg_syscall( "unlink %s", dest ); + vg_syscall( "ln -srf %s %s", folder, dest ); } -void vg_build_link( const char *link ) +void vg_tarball_project( struct vg_project *proj ) { - strcat( vg_compiler.link, link ); + vg_syscall( "tar -chzvf dist/%s-%u.tar.gz %s/", + proj->uid.buffer, time(NULL), proj->bin_folder.buffer ); } -void vg_build_include( const char *inc ) +bool vg_platform_posix( enum platform p ) { - strcat( vg_compiler.include, inc ); + if( p == k_platform_linux ) return 1; + else return 0; } -const char *vg_compiler_str(void) +/* + * Project + * -------------------------------------------------------------------------- */ + +/* Initialize the project structure, proj, + * IN folder/name, + * CLEAR IF fresh + */ +void vg_project_init( struct vg_project *proj, + const char *folder, + const char *name, + struct vg_compiler_env *env, + bool fresh ) { - return (const char *[]){ "clang", "gcc", "i686-w64-mingw32-gcc" } - [vg_compiler.compiler]; -} + vg_strnull( &proj->uid, NULL, 0 ); + vg_strcat( &proj->uid, name ); -void vg_build_start( const char *name, enum compiler compiler ) -{ - 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( env ) + { + vg_strcat( &proj->uid, "-" ); + vg_strcat( &proj->uid, platform_names[ env->platform ] ); + vg_strcat( &proj->uid, "-" ); + vg_strcat( &proj->uid, architecture_names[ env->arch ] ); + vg_strcat( &proj->uid, "-" ); + vg_strcat( &proj->uid, compiler_names[ env->compiler ] ); + } + + vg_strnull( &proj->bin_folder, NULL, 0 ); + vg_strcat( &proj->bin_folder, folder ); + vg_strcat( &proj->bin_folder, "/" ); + vg_strcat( &proj->bin_folder, proj->uid.buffer ); + + vg_info( "project_init: %s (fresh: %s)\n (%s)\n", + name, + fresh? "yes":"no", + proj->bin_folder.buffer ); + + if( fresh ) + vg_syscall( "rm -rf %s", proj->bin_folder.buffer ); + vg_syscall( "mkdir -p %s", proj->bin_folder.buffer ); } -void vg_build_add_link_for_graphics(void) +struct compile_result +{ + vg_str path, + rel_path; +}; + +/* run a compiler.. return compiled object relative to project folder + */ +struct compile_result +vg_compiler_run( struct vg_project *project, + struct vg_compiler_env *env, + struct vg_compiler_conf *conf, + const char *sources, + const char *target_name, + enum obj_type type ) { - if( (vg_compiler.compiler == k_compiler_gcc) || - (vg_compiler.compiler == k_compiler_clang ) ) + /* check for problems in configuration */ + if( env->libc != k_libc_version_native ) { - vg_build_link( "-lSDL2 -lGL -lX11 -lXxf86vm -lXrandr -lXi -ldl " ); + if( env->compiler != k_compiler_zigcc ) + { + vg_fatal_condition(); + vg_info( + "Cannot specify libc version using the '%s' compiler.\n", + compiler_names[ env->compiler ] ); + vg_fatal_exit(); + } } - else + + if( env->compiler == k_compiler_clang ) { - vg_build_link( "-lmingw32 -lSDL2main -lSDL2 -lopengl32 -mwindows " ); + if( env->platform != k_platform_linux ) + { + vg_fatal_condition(); + vg_info( "Cannot compile for '%s' using the '%s' compiler;" ); + vg_fatal_exit(); + } } - vg_build_object( "vg/dep/glad/glad.c " ); - vg_build_link( "-lm -pthread " ); -} + vg_str cmd = {0}; + vg_strcat( &cmd, "ccache " ); -void vg_build_add_link_for_game(void) -{ - if( (vg_compiler.compiler == k_compiler_gcc) || - (vg_compiler.compiler == k_compiler_clang ) ) + /* compiler specification */ + + if( env->compiler == k_compiler_zigcc ) + vg_strcat( &cmd, "zig cc " ); + else if( env->compiler == k_compiler_clang ) + vg_strcat( &cmd, "clang" ); + + vg_strcat( &cmd, " -std=gnu99 -D_REENTRANT \\\n" ); + + if( env->optimization ) { - vg_build_link( "-lsteam_api " ); + vg_strcat( &cmd, " -O" ); + vg_strcati32( &cmd, env->optimization ); } - else + else { - vg_build_library_dir( "-L./vg/dep/sdl " ); - vg_build_link( "vg/dep/steam/steam_api.dll " ); + vg_strcat( &cmd, " -O0 -ggdb3 -fno-omit-frame-pointer " ); + vg_strcat( &cmd, "\\\n" ); } - vg_build_include( "-I./vg/dep " ); - vg_build_library_dir( "-L./vg/dep/steam " ); -} + if( (env->compiler == k_compiler_clang) && env->debug_asan ) + { + vg_strcat( &cmd, " -rdynamic -fsanitize=address -fPIE " + "-fstack-protector-strong " ); + } -void vg_build_bin_dependency_file( const char *src ) -{ - vg_build_syscall( "cp %s %s", src, vg_compiler.build_dir ); -} + /* always want this */ + vg_strcat( &cmd, " -flto \\\n" ); -void vg_build_symbolic_link( const char *folder, const char *bin_name ) -{ - char dest[512]; - snprintf( dest, 512, "%s/%s", vg_compiler.build_dir, bin_name ); + /* 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( !access( dest, F_OK ) ) - vg_build_syscall( "unlink %s", dest ); + if( env->compiler != k_compiler_clang ) + vg_strcat( &cmd, " -Wno-format-truncation\\\n" ); - vg_build_syscall( "ln -srf %s %s", folder, dest ); -} + /* defines */ + vg_strcat( &cmd, " " ); + vg_strcat( &cmd, conf->defines.buffer ); + vg_strcat( &cmd, "\\\n" ); -void vg_build_copy_graphics_dependencies(void) -{ - if( vg_compiler.compiler == k_compiler_mingw ) + /* include paths */ + vg_strcat( &cmd, " " ); + vg_strcat( &cmd, conf->include.buffer ); + vg_strcat( &cmd, "\\\n" ); + + /* library paths */ + vg_strcat( &cmd, " " ); + vg_strcat( &cmd, conf->library.buffer ); + vg_strcat( &cmd, "\\\n" ); + + /* sources */ + vg_strcat( &cmd, " " ); + + if( type == k_obj_type_obj ) + vg_strcat( &cmd, "-c -fPIC " ); + + if( type == k_obj_type_shared ) { - vg_build_bin_dependency_file( "vg/dep/sdl/SDL2.dll" ); + vg_strcat( &cmd, "-shared -fPIC " ); } -} -void vg_build_copy_game_dependencies(void) -{ - vg_build_bin_dependency_file( - "vg/submodules/SDL_GameControllerDB/gamecontrollerdb.txt" ); + vg_strcat( &cmd, sources ); + vg_strcat( &cmd, "\\\n" ); - if( (vg_compiler.compiler == k_compiler_gcc) || - (vg_compiler.compiler == k_compiler_clang) ) + struct compile_result res = {0}; + + vg_strcat( &res.rel_path, target_name ); + + if( env->platform == k_platform_windows ) { - vg_build_bin_dependency_file( "vg/dep/steam/libsteam_api.so" ); + if( type == k_obj_type_exe ) + vg_strcat( &res.rel_path, ".exe" ); + else if( type == k_obj_type_shared ) + vg_strcat( &res.rel_path, ".dll" ); + else if( type == k_obj_type_obj ) + vg_strcat( &res.rel_path, ".obj" ); } - else + + if( vg_platform_posix( env->platform ) ) { - vg_build_bin_dependency_file( "vg/dep/steam/steam_api.dll" ); + if( type == k_obj_type_shared ) + vg_strcat( &res.rel_path, ".so" ); + else if( type == k_obj_type_obj ) + vg_strcat( &res.rel_path, ".o" ); } -} -void vg_build_mode_release(void) -{ - vg_compiler.optimization_profile = k_optimization_profile_release; + vg_strcat( &res.path, project->bin_folder.buffer ); + vg_strcat( &res.path, "/" ); + vg_strcat( &res.path, res.rel_path.buffer ); + + vg_strcat( &cmd, " -o " ); + vg_strcat( &cmd, res.path.buffer ); + vg_strcat( &cmd, "\\\n" ); + + /* link */ + vg_strcat( &cmd, " " ); + vg_strcat( &cmd, conf->link.buffer ); + vg_strcat( &cmd, "\\\n" ); + + if( type == k_obj_type_exe ) + { + vg_strcat( &cmd, " -Wl,-rpath=./\\\n" ); + } + + /* platform specification (zig-cc only) */ + if( env->compiler == k_compiler_zigcc ) + { + vg_strcat( &cmd, " -target " ); + vg_strcat( &cmd, architecture_names[env->arch] ); + vg_strcat( &cmd, "-" ); + vg_strcat( &cmd, platform_names[env->platform] ); + + if( env->platform == k_platform_linux ) + { + vg_strcat( &cmd, "-gnu" ); + vg_strcat( &cmd, libc_names[env->libc] ); + } + + if( env->platform == k_platform_windows ) + { + /* we currently dont want pdb pretty much ever. goodbye! */ + + if( type == k_obj_type_exe ) + { + vg_strcat( &cmd, " /pdb:/dev/null" ); + vg_strcat( &cmd, " /SUBSYSTEM:windows" ); + } + } + } + + vg_syscall( cmd.buffer ); + return res; } -void vg_build_mode_debug(void) +/* + * Standard VG includes & libraries which we use for games/graphics + * -------------------------------------------------------------------------- */ + +struct vg_engine_config { - vg_compiler.optimization_profile = k_optimization_profile_debug; + bool use_3d, + legacy_support_vg_msg1, + log_source_info, + steam_api, + custom_game_settings, + custom_shaders; + i32 fixed_update_hz; } - -void vg_build(void) +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 +}; + +struct compile_result +vg_make_app( struct vg_project *proj, + struct vg_engine_config *vg_conf, + struct vg_compiler_env *env, + struct vg_compiler_conf *conf, + const char *sources, + const char *appname ) { - char cmd[4096]; - cmd[0] = '\0'; + struct vg_project vg_proj; + vg_project_init( &vg_proj, "bin", ".vg", env, 0 ); - /* Compiler */ - strcat( cmd, "ccache " ); - strcat( cmd, vg_compiler_str() ); - strcat( cmd, " -std=gnu99 -D_REENTRANT \\\n" ); + /* building assets */ + vg_build_default_font(); - /* Debugging information */ - if( vg_compiler.optimization_profile == k_optimization_profile_debug ) - { - strcat( cmd, " -O0 -ggdb3 -fno-omit-frame-pointer " ); + /* add config defines to compiler config */ + if( !vg_conf ) vg_conf = &vg_engine_default_config; + vg_strcat( &conf->defines, vg_conf->use_3d? "-DVG_3D \\\n": "-DVG_2D \\\n" ); + vg_strcatf( &conf->defines, "-DVG_TIMESTEP_FIXED=\"(1.0/%d.0)\" \\\n", + vg_conf->fixed_update_hz ); - if( (vg_compiler.compiler == k_compiler_gcc) || - (vg_compiler.compiler == k_compiler_clang ) ) - { - strcat( cmd, "-rdynamic -fsanitize=address " ); - } + if( vg_conf->legacy_support_vg_msg1 ) + vg_strcat( &conf->defines, "-DVG_MSG_V1_SUPPORT \\\n" ); - strcat( cmd, "\\\n" ); - } - else - { - strcat( cmd, " -O3 -DVG_RELEASE\\\n" ); - } + if( vg_conf->log_source_info ) + vg_strcat( &conf->defines, "-DVG_LOG_SOURCE_INFO \\\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" - ); + if( vg_conf->custom_game_settings ) + vg_strcat( &conf->defines, "-DVG_GAME_SETTINGS \\\n" ); - /* Include */ - strcat( cmd, " " ); - strcat( cmd, vg_compiler.include ); - strcat( cmd, "\\\n" ); + if( vg_conf->custom_shaders ) + vg_strcat( &conf->defines, "-DVG_CUSTOM_SHADERS \\\n" ); - /* Library */ - strcat( cmd, " " ); - strcat( cmd, vg_compiler.library ); - strcat( cmd, "\\\n" ); + if( env->arch == k_architecture_i386 ) + vg_strcat( &conf->defines, "-DVG_32 \\\n" ); + else + vg_strcat( &conf->defines, "-DVG_64 \\\n" ); + + vg_strcat( &conf->defines, "\\\n" ); + vg_strcat( &conf->include, "-I. -I./vg -I./vg/dep " ); + + /* compile all the components + * ----------------------------------------------------------------------- */ + vg_str components = {0}; + vg_strcatf( &components, "%s ", sources ); + + struct vg_compiler_env denv = *env; + //denv.optimization = 3; + + /* external dependencies */ + struct compile_result depencies = + vg_compiler_run( &vg_proj, &denv, conf, "vg/vg_depencies.c", + "vg_deps", k_obj_type_obj ); + vg_strcatf( &components, "%s ", depencies.path ); + + /* glad */ + struct compile_result glad = + vg_compiler_run( &vg_proj, &denv, conf, "vg/dep/glad/glad.c", + "vg_glad", k_obj_type_obj ); + vg_strcatf( &components, "%s ", glad.path ); + + /* core engine */ + struct compile_result vg = + vg_compiler_run( &vg_proj, &denv, conf, "vg/vg_engine.c", + "vg_engine_core", k_obj_type_obj ); + vg_strcatf( &components, "%s ", vg.path ); + + /* steamworks */ + if( vg_conf->steam_api ) + { + struct compile_result steam = + vg_compiler_run( &vg_proj, &denv, conf, "vg/vg_steam.c", + "vg_steam", k_obj_type_obj ); + vg_strcatf( &components, "%s ", steam.path ); - /* Targets */ - strcat( cmd, " " ); - strcat( cmd, vg_compiler.file ); - strcat( cmd, "\\\n" ); + if( env->platform == k_platform_linux ) + { + vg_add_blob( proj, "vg/dep/steam/libsteam_api.so", "" ); + vg_strcat( &conf->link, "-lsteam_api " ); + } + else if( env->platform == k_platform_windows ) + { + vg_add_blob( proj, "vg/dep/steam/steam_api64.dll", "" ); + vg_strcat( &conf->link, "vg/dep/steam/steam_api64.dll " ); + } - /* 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 ); + vg_strcat( &conf->library, "-L./vg/dep/steam " ); + } - if( vg_compiler.compiler == k_compiler_mingw ) - strcat( vg_compiler.executable, ".exe" ); + /* link */ + vg_strcat( &conf->library, "-L. -L/usr/lib " ); + vg_strcat( &conf->link, "-lm " ); - strcat( cmd, vg_compiler.executable ); - strcat( cmd, "\\\n" ); + if( env->platform == k_platform_linux ) + { + vg_strcat( &conf->link, "-lSDL2 -lGL -lX11 -lXxf86vm " + "-lXrandr -lXi -ldl -pthread " ); - /* Link */ - strcat( cmd, " " ); - strcat( cmd, vg_compiler.link ); - strcat( cmd, "\\\n" ); + return vg_compiler_run( proj, env, conf, components.buffer, + appname, k_obj_type_exe ); + } + else if( env->platform == k_platform_windows ) + { + vg_strcat( &conf->link, "-lSDL2main -lSDL2 -lopengl32 \\\n" ); + vg_strcat( &conf->link, "vg/dep/sdl/SDL2.dll " ); + vg_add_blob( proj, "vg/dep/sdl/SDL2.dll ", "" ); + vg_strcat( &conf->library, "-L./vg/dep/sdl " ); - strcat( cmd, " -Wl,-rpath=./" ); + return vg_compiler_run( proj, env, conf, components.buffer, + appname, k_obj_type_exe ); + } + else + { + vg_fatal_condition(); + vg_info( "No compile procedure set for platform '%s'\n", + platform_names[env->platform] ); + vg_fatal_exit(); + } - vg_build_syscall( cmd ); + return (struct compile_result){}; +} + +void vg_add_controller_database( struct vg_project *proj ) +{ + vg_add_blob( proj, + "vg/submodules/SDL_GameControllerDB/gamecontrollerdb.txt", "" ); }