move explicit bezier to vg
[vg.git] / vg_build.h
index 965f14cac3941c73e687985360410d581b5008a3..9a1d861ab45f12c05ccc57c7809d86eb5cdf7529 100644 (file)
-/* zig cc scripting tools */
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <time.h>
+#include <stdarg.h>
 
+#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_project
+{
+   vg_str uid, bin_folder;
+};
 
-   u32 optimization,
-       warnings;
-   bool fresh,
-        debug_asan;
+struct vg_compiler_env
+{
+   u32 optimization;
+   bool debug_asan;
 
-   enum platform {
+   enum platform 
+   {
       k_platform_anyplatform,
       k_platform_windows,
-      k_platform_linux
+      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
+      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 };
+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 const char *platform_names[] = {
+static const char *platform_names[] = 
+{
    [k_platform_anyplatform] = "anyplatform",
    [k_platform_windows]     = "windows",
-   [k_platform_linux]       = "linux"
+   [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"
+   [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"
+   [k_compiler_zigcc]   = "zig-cc",
 };
 
-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"
 };
 
-/*
- * source specification
- * -------------------------------------------------------------------------- */
-
-void vg_add_source( const char *source ){
-   vg_strcat( &vg_build.sources, source );
-   vg_strcat( &vg_build.sources, " " );
-}
-
-void vg_include_dir( const char *dir ){
-   vg_strcat( &vg_build.include, dir );
-   vg_strcat( &vg_build.include, " " );
-}
-
-void vg_library_dir( const char *dir ){
-   vg_strcat( &vg_build.library, dir );
-   vg_strcat( &vg_build.library, " " );
-}
-
-void vg_link( const char *lib ){
-   vg_strcat( &vg_build.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,201 +137,402 @@ 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 %s/%s", blob, proj->bin_folder.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, "%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_tarball_last_project(void){
-   vg_syscall( "tar -chzvf dist/%s-%u.tar.gz bin/%s/",
-               vg_build.project_name.buffer, time(NULL),
-               vg_build.project_name.buffer );
+void vg_tarball_project( struct vg_project *proj )
+{
+   vg_syscall( "tar -chzvf dist/%s-%u.tar.gz %s/",
+               proj->uid.buffer, time(NULL), proj->bin_folder.buffer );
 }
 
+bool vg_platform_posix( enum platform p )
+{
+   if( p == k_platform_linux ) return 1;
+   else return 0;
+}
 
 /*
- * Standard VG includes & libraries which we use for games/graphics
+ * Project
  * -------------------------------------------------------------------------- */
 
-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" );
-}
+/* 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 )
+{
+   vg_strnull( &proj->uid, NULL, 0 );
+   vg_strcat( &proj->uid, name );
+
+   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 ] );
+   }
 
-void vg_add_game_stuff(void){
-   vg_add_blob( "vg/submodules/SDL_GameControllerDB/gamecontrollerdb.txt", "" );
+   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 );
 
-   if( vg_build.platform == k_platform_linux ){
-      vg_add_blob( "vg/dep/steam/libsteam_api.so", "" );
-      vg_link( "-lsteam_api " );
-   }
-   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 " );
-   }
+   vg_info( "project_init: %s (fresh: %s)\n   (%s)\n", 
+               name, 
+               fresh? "yes":"no",
+               proj->bin_folder.buffer );
 
-   vg_include_dir( "-I./vg/dep " );
-   vg_library_dir( "-L./vg/dep/steam " );
+   if( fresh )
+      vg_syscall( "rm -rf %s", proj->bin_folder.buffer );
+   vg_syscall( "mkdir -p %s", proj->bin_folder.buffer );
 }
 
-/*
- * The project configurator and compiler.
- * -------------------------------------------------------------------------- */
-
-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 );
+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 )
+{
    /* 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_condition();
+         vg_info(
+               "Cannot specify libc version using the '%s' compiler.\n",
+               compiler_names[ env->compiler ] );
+         vg_fatal_exit();
       }
    }
 
-   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_condition();
+         vg_info( "Cannot compile for '%s' using the '%s' compiler;" );
+         vg_fatal_exit();
       }
    }
 
-   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_str cmd = {0};
+   vg_strcat( &cmd, "ccache " );
 
-   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" );
-}
+   /* compiler specification */
 
-void vg_compile( const char *name ){
-   vg_str cmd;
-   vg_strnull( &cmd, NULL, -1 );
+   if( env->compiler == k_compiler_zigcc ) 
+      vg_strcat( &cmd, "zig cc " );
+   else if( env->compiler == k_compiler_clang )
+      vg_strcat( &cmd, "clang" );
 
-   /* compiler specification */
-   vg_strcat( &cmd, "ccache " );
-   vg_strcat( &cmd, compiler_paths[ vg_build.compiler ] );
    vg_strcat( &cmd, " -std=gnu99 -D_REENTRANT \\\n" );
 
-   if( vg_build.optimization ){
+   if( env->optimization )
+   {
       vg_strcat( &cmd, "  -O" );
-      vg_strcati32( &cmd, vg_build.optimization );
-      vg_strcat( &cmd, " -DVG_RELEASE\\\n" );
+      vg_strcati32( &cmd, env->optimization );
    }
-   else {
-      /* add debugger / asan information */
+   else 
+   {
       vg_strcat( &cmd, "  -O0 -ggdb3 -fno-omit-frame-pointer " );
-
-      if( (vg_build.compiler == k_compiler_clang) && vg_build.debug_asan ){
-         vg_strcat( &cmd, "  -rdynamic -fsanitize=address -fPIE "
-                          "-fstack-protector-strong " );
-      }
-
       vg_strcat( &cmd, "\\\n" );
    }
 
+   if( (env->compiler == k_compiler_clang) && env->debug_asan )
+   {
+      vg_strcat( &cmd, "  -rdynamic -fsanitize=address -fPIE "
+                       "-fstack-protector-strong " );
+   }
+
+   /* always want this */
+   vg_strcat( &cmd, " -flto \\\n" );
+
    /* 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( env->compiler != k_compiler_clang )
+      vg_strcat( &cmd, "    -Wno-format-truncation\\\n" );
+
+   /* defines */
+   vg_strcat( &cmd, "  " );
+   vg_strcat( &cmd, conf->defines.buffer );
+   vg_strcat( &cmd, "\\\n" );
+
    /* include paths */
    vg_strcat( &cmd, "  " );
-   vg_strcat( &cmd, vg_build.include.buffer );
+   vg_strcat( &cmd, conf->include.buffer );
    vg_strcat( &cmd, "\\\n" );
    
    /* library paths */
    vg_strcat( &cmd, "  " );
-   vg_strcat( &cmd, vg_build.library.buffer );
+   vg_strcat( &cmd, conf->library.buffer ); 
    vg_strcat( &cmd, "\\\n" );
 
    /* sources */
    vg_strcat( &cmd, "  " );
-   vg_strcat( &cmd, vg_build.sources.buffer );
+
+   if( type == k_obj_type_obj )
+      vg_strcat( &cmd, "-c -fPIC " );
+
+   if( type == k_obj_type_shared )
+   {
+      vg_strcat( &cmd, "-shared -fPIC " );
+   }
+
+   vg_strcat( &cmd, sources );
    vg_strcat( &cmd, "\\\n" );
 
-   /* output */
-   vg_strcat( &cmd, "  -o bin/" );
-   vg_strcat( &cmd, vg_build.project_name.buffer );
-   vg_strcat( &cmd, "/" );
-   vg_strcat( &cmd, name );
-   if( vg_build.platform == k_platform_windows )
-      vg_strcat( &cmd, ".exe" );
+   struct compile_result res = {0};
+
+   vg_strcat( &res.rel_path, target_name );
+
+   if( env->platform == k_platform_windows )
+   {
+      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" );
+   }
+
+   if( vg_platform_posix( env->platform ) )
+   {
+      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" );
+   }
+
+   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, vg_build.link.buffer );
+   vg_strcat( &cmd, conf->link.buffer );
    vg_strcat( &cmd, "\\\n" );
    
-   /* dont remember what this does */
-   vg_strcat( &cmd, "  -Wl,-rpath=./\\\n" );
+   if( type == k_obj_type_exe )
+   {
+      vg_strcat( &cmd, "  -Wl,-rpath=./\\\n" );
+   }
 
-   /* target platform specification (zig-cc only) */
-   if( vg_build.compiler == k_compiler_zigcc ){
+   /* platform specification (zig-cc only) */
+   if( env->compiler == k_compiler_zigcc )
+   {
       vg_strcat( &cmd, "  -target " );
-      vg_strcat( &cmd, architecture_names[vg_build.arch] );
+      vg_strcat( &cmd, architecture_names[env->arch] );
       vg_strcat( &cmd, "-" );
-      vg_strcat( &cmd, platform_names[vg_build.platform] );
+      vg_strcat( &cmd, platform_names[env->platform] );
 
-      if( vg_build.platform == k_platform_linux ){
+      if( env->platform == k_platform_linux )
+      {
          vg_strcat( &cmd, "-gnu" );
-         vg_strcat( &cmd, libc_names[vg_build.libc] );
+         vg_strcat( &cmd, libc_names[env->libc] );
       }
 
-      if( vg_build.platform == k_platform_windows ){
+      if( env->platform == k_platform_windows )
+      {
          /* we currently dont want pdb pretty much ever. goodbye! */
-         vg_strcat( &cmd, " /SUBSYSTEM:windows /pdb:/dev/null" );
+
+         if( type == k_obj_type_exe )
+         {
+            vg_strcat( &cmd, " /pdb:/dev/null" );
+            vg_strcat( &cmd, " /SUBSYSTEM:windows" );
+         }
       }
    }
 
    vg_syscall( cmd.buffer );
+   return res;
+}
+
+/*
+ * 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
+};
+
+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 )
+{
+   struct vg_project vg_proj;
+   vg_project_init( &vg_proj, "bin", ".vg", env, 0 );
+
+   /* building assets */
+   vg_build_default_font();
+
+   /* 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_conf->legacy_support_vg_msg1 )
+      vg_strcat( &conf->defines, "-DVG_MSG_V1_SUPPORT \\\n" );
+
+   if( vg_conf->log_source_info )
+      vg_strcat( &conf->defines, "-DVG_LOG_SOURCE_INFO \\\n" );
+
+   if( vg_conf->custom_game_settings )
+      vg_strcat( &conf->defines, "-DVG_GAME_SETTINGS \\\n" );
+
+   if( vg_conf->custom_shaders )
+      vg_strcat( &conf->defines, "-DVG_CUSTOM_SHADERS \\\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 );
+
+      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 " );
+      }
+
+      vg_strcat( &conf->library, "-L./vg/dep/steam " );
+   }
+
+   /* link */
+   vg_strcat( &conf->library, "-L. -L/usr/lib " );
+   vg_strcat( &conf->link, "-lm " );
+
+   if( env->platform == k_platform_linux )
+   {
+      vg_strcat( &conf->link, "-lSDL2 -lGL -lX11 -lXxf86vm "
+                              "-lXrandr -lXi -ldl -pthread " );
+
+      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 " );
+
+      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();
+   }
+
+   return (struct compile_result){};
+}
+
+void vg_add_controller_database( struct vg_project *proj )
+{
+   vg_add_blob( proj, 
+                "vg/submodules/SDL_GameControllerDB/gamecontrollerdb.txt", "" );
 }