4coder/bin/4ed_build.cpp

699 lines
20 KiB
C++

/*
* Mr. 4th Dimention - Allen Webster
*
* ??.??.????
*
* 4coder development build rule.
*
*/
// TOP
//#define FM_PRINT_COMMANDS
#include "4coder_base_types.h"
#include "4coder_version.h"
#include "4coder_base_types.cpp"
#include "4coder_malloc_allocator.cpp"
#define FTECH_FILE_MOVING_IMPLEMENTATION
#include "4coder_file_moving.h"
//
// OS and compiler index
//
enum{
Platform_Windows,
Platform_Linux,
Platform_Mac,
//
Platform_COUNT,
Platform_None = Platform_COUNT,
};
char *platform_names[] = {
"win",
"linux",
"mac",
};
enum{
Compiler_CL,
Compiler_GCC,
//
Compiler_COUNT,
Compiler_None = Compiler_COUNT,
};
char *compiler_names[] = {
"cl",
"gcc",
};
#if OS_WINDOWS
# define This_OS Platform_Windows
#elif OS_LINUX
# define This_OS Platform_Linux
#elif OS_MAC
# define This_OS Platform_Mac
#else
# error This platform is not enumerated.
#endif
#if COMPILER_CL
# define This_Compiler Compiler_CL
#elif COMPILER_GCC
# define This_Compiler Compiler_GCC
#else
# error This compilers is not enumerated.
#endif
//
// Universal directories
//
#define BUILD_DIR "../build"
#define PACK_DIR "../distributions"
#define SITE_DIR "../site"
#define FOREIGN "../4coder-non-source/foreign"
#define FOREIGN_WIN "..\\4coder-non-source\\foreign"
char *includes[] = { "custom", FOREIGN "/freetype2", 0, };
//
// Platform layer file tables
//
char *windows_platform_layer[] = { "platform_win32/win32_4ed.cpp", 0 };
char *linux_platform_layer[] = { "platform_linux/linux_4ed.cpp", 0 };
char *mac_platform_layer[] = { "platform_mac/mac_4ed.m", "platform_mac/mac_4ed.cpp", 0 };
char **platform_layers[Platform_COUNT] = {
windows_platform_layer,
linux_platform_layer ,
mac_platform_layer ,
};
char *windows_cl_platform_inc[] = { "platform_all", 0 };
char *linux_gcc_platform_inc[] = { "platform_all", "platform_unix", 0 };
char *mac_gcc_platform_inc[] = { "platform_all", "platform_unix", 0 };
char **platform_includes[Platform_COUNT][Compiler_COUNT] = {
{windows_cl_platform_inc, 0 },
{0 , linux_gcc_platform_inc},
{0 , mac_gcc_platform_inc },
};
//
// Custom targets
//
enum{
Custom_Default,
//
Custom_COUNT
};
char *custom_files[] = {
"../code/custom/4coder_default_bindings.cpp",
};
//
// Architectures
//
enum{
Arch_X64,
Arch_X86,
//
Arch_COUNT,
Arch_None = Arch_COUNT,
};
char *arch_names[] = {
"x64",
"x86",
};
//
// Build flags
//
enum{
OPTS = 0x1,
LIBS = 0x2,
ICON = 0x4,
SHARED_CODE = 0x8,
DEBUG_INFO = 0x10,
OPTIMIZATION = 0x20,
SUPER = 0x40,
INTERNAL = 0x80,
KEEP_ASSERT = 0x100,
};
internal char**
get_defines_from_flags(Arena *arena, u32 flags){
char **result = 0;
if (HasFlag(flags, KEEP_ASSERT)){
result = fm_list(arena, fm_list_one_item(arena, "FRED_KEEP_ASSERT"), result);
}
if (HasFlag(flags, INTERNAL)){
result = fm_list(arena, fm_list_one_item(arena, "FRED_INTERNAL"), result);
}
if (HasFlag(flags, SUPER)){
result = fm_list(arena, fm_list_one_item(arena, "FRED_SUPER"), result);
}
return(result);
}
//
// build implementation: cl
//
#if COMPILER_CL
#define CL_OPTS \
"-W4 -wd4310 -wd4100 -wd4201 -wd4505 -wd4996 " \
"-wd4127 -wd4510 -wd4512 -wd4610 -wd4390 " \
"-wd4611 -wd4189 -WX -GR- -EHa- -nologo -FC"
#define CL_LIBS_X64 \
"user32.lib winmm.lib gdi32.lib opengl32.lib comdlg32.lib " \
FOREIGN_WIN "\\x64\\freetype.lib"
#define CL_LIBS_X86 \
"user32.lib winmm.lib gdi32.lib opengl32.lib comdlg32.lib " \
FOREIGN_WIN "\\x86\\freetype.lib"
#define CL_ICON "..\\4coder-non-source\\res\\icon.res"
internal void
build(Arena *arena, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){
Temp_Dir temp = fm_pushdir(out_path);
Build_Line line;
fm_init_build_line(&line);
if (arch == Arch_X86){
fm_add_to_line(line, "%s\\windows_scripts\\setup_cl_x86.bat &", code_path);
}
fm_add_to_line(line, "cl");
if (flags & OPTS){
fm_add_to_line(line, CL_OPTS);
}
switch (arch){
case Arch_X64: fm_add_to_line(line, "-DFTECH_64_BIT"); break;
case Arch_X86: fm_add_to_line(line, "-DFTECH_32_BIT"); break;
default: InvalidPath;
}
fm_add_to_line(line, "-I%s", code_path);
if (inc_folders != 0){
for (u32 i = 0; inc_folders[i] != 0; ++i){
char *str = fm_str(arena, code_path, "/", inc_folders[i]);
fm_add_to_line(line, "-I%s", str);
}
}
if (flags & LIBS){
switch (arch){
case Arch_X64: fm_add_to_line(line, CL_LIBS_X64); break;
case Arch_X86: fm_add_to_line(line, CL_LIBS_X86); break;
default: InvalidPath;
}
}
if (flags & ICON){
fm_add_to_line(line, CL_ICON);
}
if (flags & DEBUG_INFO){
fm_add_to_line(line, "-Zi");
fm_add_to_line(line, "-DDO_CRAZY_EXPENSIVE_ASSERTS");
}
if (flags & OPTIMIZATION){
fm_add_to_line(line, "-O2");
}
if (flags & SHARED_CODE){
fm_add_to_line(line, "-LD");
}
if (defines != 0){
for (u32 i = 0; defines[i] != 0; ++i){
char *define_flag = fm_str(arena, "-D", defines[i]);
fm_add_to_line(line, "%s", define_flag);
}
}
for (u32 i = 0; code_files[i]; ++i){
fm_add_to_line(line, "\"%s\\%s\"", code_path, code_files[i]);
}
fm_add_to_line(line, "-Fe%s", out_file);
fm_add_to_line(line, "-link -INCREMENTAL:NO -RELEASE -PDBALTPATH:%%_PDB%%");
switch (arch){
case Arch_X64: fm_add_to_line(line, "-MACHINE:X64"); break;
case Arch_X86: fm_add_to_line(line, "-MACHINE:X86"); break;
default: InvalidPath;
}
if (flags & DEBUG_INFO){
fm_add_to_line(line, "-DEBUG");
}
if (flags & SHARED_CODE){
Assert(exports != 0);
fm_add_to_line(line, "-OPT:REF");
for (u32 i = 0; exports[i] != 0; ++i){
char *str = fm_str(arena, "-EXPORT:", exports[i]);
fm_add_to_line(line, "%s", str);
}
}
else{
fm_add_to_line(line, "-NODEFAULTLIB:library");
}
fm_finish_build_line(&line);
systemf("%s", line.build_options);
fm_popdir(temp);
}
//
// build implementation: gcc
//
#elif COMPILER_GCC
#if OS_LINUX
# define GCC_OPTS \
"-Wno-write-strings " \
"-D_GNU_SOURCE -fPIC " \
"-fno-threadsafe-statics -pthread " \
"-Wno-unused-result"
#define GCC_LIBS_COMMON \
"-lX11 -lpthread -lm -lrt " \
"-lGL -ldl -lXfixes -lfreetype -lfontconfig"
#define GCC_LIBS_X64 GCC_LIBS_COMMON
#define GCC_LIBS_X86 GCC_LIBS_COMMON
#elif OS_MAC
# define GCC_OPTS \
"-Wno-write-strings -Wno-deprecated-declarations " \
"-Wno-comment -Wno-switch -Wno-null-dereference " \
"-Wno-tautological-compare " \
"-Wno-unused-result "
#define GCC_LIBS_COMMON \
"-framework Cocoa -framework QuartzCore " \
"-framework CoreServices " \
"-framework OpenGL -framework IOKit "
#define GCC_LIBS_X64 GCC_LIBS_COMMON \
FOREIGN "/x64/libfreetype-mac.a"
#define GCC_LIBS_X86 GCC_LIBS_COMMON \
FOREIGN "/x86/libfreetype-mac.a"
#else
# error gcc options not set for this platform
#endif
internal void
build(Partition *part, u32 flags, u32 arch, char *code_path, char **code_files, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){
Build_Line line;
fm_init_build_line(&line);
switch (arch){
case Arch_X64:
fm_add_to_line(line, "-m64");
fm_add_to_line(line, "-DFTECH_64_BIT"); break;
case Arch_X86:
fm_add_to_line(line, "-m32");
fm_add_to_line(line, "-DFTECH_32_BIT"); break;
default: InvalidCodePath;
}
if (flags & OPTS){
fm_add_to_line(line, GCC_OPTS);
}
fm_add_to_line(line, "-I%s", code_path);
if (inc_folders != 0){
for (u32 i = 0; inc_folders[i] != 0; ++i){
char *str = fm_str(part, code_path, "/", inc_folders[i]);
fm_add_to_line(line, "-I%s", str);
}
}
if (flags & DEBUG_INFO){
fm_add_to_line(line, "-g -O0");
}
if (flags & OPTIMIZATION){
fm_add_to_line(line, "-O3");
}
if (flags & SHARED_CODE){
fm_add_to_line(line, "-shared");
}
if (defines != 0){
for (u32 i = 0; defines[i]; ++i){
char *define_flag = fm_str(part, "-D", defines[i]);
fm_add_to_line(line, "%s", define_flag);
}
}
fm_add_to_line(line, "-I\"%s\"", code_path);
for (u32 i = 0; code_files[i] != 0; ++i){
fm_add_to_line(line, "\"%s/%s\"", code_path, code_files[i]);
}
if (flags & LIBS){
if (arch == Arch_X64){
fm_add_to_line(line, GCC_LIBS_X64);
}
else if (arch == Arch_X86)
{
fm_add_to_line(line, GCC_LIBS_X86);
}
}
fm_finish_build_line(&line);
Temp_Dir temp = fm_pushdir(out_path);
systemf("g++ %s -o %s", line.build_options, out_file);
fm_popdir(temp);
}
#else
# error build function not defined for this compiler
#endif
internal void
build(Arena *arena, u32 flags, u32 arch, char *code_path, char *code_file, char *out_path, char *out_file, char **defines, char **exports, char **inc_folders){
char **code_files = fm_list_one_item(arena, code_file);
build(arena, flags, arch, code_path, code_files, out_path, out_file, defines, exports, inc_folders);
}
// TODO(NAME): build metadata fully from C++ and eliminate build_metadata.bat and build_metadata.sh
internal void
build_metadata(void){
systemf(".%s%s ..%scode%s4coder_default_bindings.cpp", SLASH, "build_metadata" BAT, SLASH, SLASH);
}
internal void
site_build(Arena *arena, char *cdir, u32 flags){
build_metadata();
{
char *file = fm_str(arena, "site/4ed_sitegen.cpp");
char *dir = fm_str(arena, BUILD_DIR);
BEGIN_TIME_SECTION();
build(arena, OPTS | flags, Arch_X64, cdir, file, dir, "sitegen", get_defines_from_flags(arena, flags), 0, includes);
END_TIME_SECTION("build sitegen");
}
if (prev_error == 0){
BEGIN_TIME_SECTION();
char *cmd = fm_str(arena, BUILD_DIR "/sitegen");
char *code_dir = fm_str(arena, ".");
char *asset_dir = fm_str(arena, "../4coder-non-source/site_resources");
char *site_source_dir = fm_str(arena, "site/source_material");
char *dest_dir = fm_str(arena, "../site");
fm_make_folder_if_missing(arena, dest_dir);
systemf("%s %s %s %s %s", cmd, code_dir, asset_dir, site_source_dir, dest_dir);
END_TIME_SECTION("run sitegen");
}
}
internal void
build_and_run(Arena *arena, char *cdir, char *filename, char *name, u32 flags){
char *dir = fm_str(arena, BUILD_DIR);
{
char *file = fm_str(arena, filename);
BEGIN_TIME_SECTION();
build(arena, flags, Arch_X64, cdir, file, dir, name, get_defines_from_flags(arena, flags), 0, includes);
END_TIME_SECTION(fm_str(arena, "build ", name));
}
if (prev_error == 0){
char *cmd = fm_str(arena, dir, "/", name);
BEGIN_TIME_SECTION();
fm_execute_in_dir(cdir, cmd, 0);
END_TIME_SECTION(fm_str(arena, "run ", name));
}
}
internal void
string_build(Arena *arena, char *cdir){
char *dir = fm_str(arena, BUILD_DIR);
{
char *file = fm_str(arena, "string/4ed_string_builder.cpp");
BEGIN_TIME_SECTION();
build(arena, OPTS | DEBUG_INFO, Arch_X64, cdir, file, dir, "string_builder", 0, 0, includes);
END_TIME_SECTION("build string_builder");
}
if (prev_error == 0){
char *cmd = fm_str(arena, cdir, "/", dir, "/string_builder");
BEGIN_TIME_SECTION();
fm_execute_in_dir(fm_str(arena, cdir, "/string"), cmd, 0);
END_TIME_SECTION("run string_builder");
}
}
internal void
do_buildsuper(Arena *arena, char *cdir, char *file, u32 arch){
BEGIN_TIME_SECTION();
Temp_Dir temp = fm_pushdir(fm_str(arena, BUILD_DIR));
char *build_script = fm_str(arena, "custom/bin/buildsuper_", arch_names[arch], BAT);
char *build_command = fm_str(arena, "\"", cdir, "/", build_script, "\" \"", file, "\"");
if (This_OS == Platform_Windows){
build_command = fm_str(arena, "call ", build_command);
}
systemf("%s", build_command);
fm_popdir(temp);
END_TIME_SECTION("build custom");
}
// TODO(allen): Remove this
internal i32
get_freetype_include(char *out, u32 max){
i32 size = 0;
#if 0
#if OS_LINUX
char freetype_include[512];
FILE *file = popen("pkg-config --cflags freetype2", "r");
if (file != 0){
fgets(freetype_include, sizeof(freetype_include), file);
size = strlen(freetype_include);
memcpy(out, freetype_include, size);
pclose(file);
}
#elif OS_MAC
char *freetype_include = "/usr/local/include/freetype2";
size = strlen(freetype_include);
memcpy(out, freetype_include, size);
#endif
#endif
return(size);
}
internal void
build_main(Arena *arena, char *cdir, b32 update_local_theme, u32 flags, u32 arch){
char *dir = fm_str(arena, BUILD_DIR);
{
char *file = fm_str(arena, "4ed_app_target.cpp");
char **exports = fm_list_one_item(arena, "app_get_functions");
char **build_includes = includes;
char ft_include[512];
i32 ft_size = get_freetype_include(ft_include, sizeof(ft_include) - 1);
if (ft_size > 0){
ft_include[ft_size] = 0;
fprintf(stdout, "FREETYPE: %s\n", ft_include);
build_includes = fm_list(arena, build_includes, fm_list_one_item(arena, ft_include));
}
BEGIN_TIME_SECTION();
build(arena, OPTS | SHARED_CODE | flags, arch, cdir, file, dir, "4ed_app" DLL, get_defines_from_flags(arena, flags), exports, build_includes);
END_TIME_SECTION("build 4ed_app");
}
{
BEGIN_TIME_SECTION();
char **inc = (char**)fm_list(arena, includes, platform_includes[This_OS][This_Compiler]);
build(arena, OPTS | LIBS | ICON | flags, arch, cdir, platform_layers[This_OS], dir, "4ed", get_defines_from_flags(arena, flags), 0, inc);
END_TIME_SECTION("build 4ed");
}
if (update_local_theme){
BEGIN_TIME_SECTION();
char *themes_folder = fm_str(arena, "../build/themes");
char *source_themes_folder = fm_str(arena, "themes");
fm_clear_folder(themes_folder);
fm_make_folder_if_missing(arena, themes_folder);
fm_copy_all(source_themes_folder, "*", themes_folder);
END_TIME_SECTION("move files");
}
}
internal void
standard_build(Arena *arena, char *cdir, u32 flags, u32 arch){
do_buildsuper(arena, cdir, fm_str(arena, custom_files[Custom_Default]), arch);
build_main(arena, cdir, true, flags, arch);
}
internal char*
get_4coder_dist_name(Arena *arena, u32 platform, char *tier, u32 arch){
char *name = fm_str(arena, "4coder-alpha-" MAJOR_STR "-" MINOR_STR "-" PATCH_STR);
if (strcmp(tier, "alpha") != 0){
name = fm_str(arena, name, "-", tier);
}
if (platform != Platform_None){
name = fm_str(arena, name, "-", platform_names[platform]);
}
if (arch != Arch_None){
name = fm_str(arena, name, "-", arch_names[arch]);
}
return(name);
}
internal void
package(Arena *arena, char *cdir){
// NOTE(allen): meta
char *build_dir = fm_str(arena, BUILD_DIR);
char *pack_dir = fm_str(arena, PACK_DIR);
char *fonts_source_dir = fm_str(arena, "../4coder-non-source/dist_files/fonts");
char *base_package_root = "../current_dist";
// NOTE(allen): alpha and super builds
enum{
Tier_Alpha = 0,
Tier_Super = 1,
Tier_COUNT = 2
};
char *tiers[] = { "alpha", "super" };
u32 base_flags = OPTIMIZATION | KEEP_ASSERT | DEBUG_INFO;
u32 tier_flags[] = { 0, SUPER, };
for (u32 tier_index = 0; tier_index < Tier_COUNT; ++tier_index){
char *tier = tiers[tier_index];
u32 flags = base_flags | tier_flags[tier_index];
Temp_Memory temp = begin_temp(arena);
char *tier_package_root = fm_str(arena, base_package_root, "_", tier);
for (u32 arch = 0; arch < Arch_COUNT; ++arch){
char *par_dir = fm_str(arena, tier_package_root, "_", arch_names[arch]);
char *dir = fm_str(arena, par_dir, "/4coder");
char *fonts_dir = fm_str(arena, dir, "/fonts");
char *zip_dir = fm_str(arena, pack_dir, "/", tier, "_", arch_names[arch]);
build_metadata();
build_main(arena, cdir, false, flags, arch);
fm_clear_folder(par_dir);
fm_make_folder_if_missing(arena, dir);
fm_copy_file(fm_str(arena, build_dir, "/4ed" EXE), fm_str(arena, dir, "/4ed" EXE));
fm_copy_file(fm_str(arena, build_dir, "/4ed_app" DLL), fm_str(arena, dir, "/4ed_app" DLL));
fm_copy_folder(arena, cdir, dir, "themes");
fm_copy_file(fm_str(arena, cdir, "/LICENSE.txt"), fm_str(arena, dir, "/LICENSE.txt"));
fm_copy_file(fm_str(arena, cdir, "/README.txt"), fm_str(arena, dir, "/README.txt"));
fm_copy_file(fm_str(arena, cdir, "/changes.txt"), fm_str(arena, dir, "/changes.txt"));
fm_make_folder_if_missing(arena, fonts_dir);
fm_copy_all(fonts_source_dir, "*", fonts_dir);
fm_copy_file(fm_str(arena, cdir, "/release-config.4coder"), fm_str(arena, dir, "/config.4coder"));
if (tier_index == Tier_Super){
fm_copy_all(0, "4coder_*", dir);
do_buildsuper(arena, cdir, fm_str(arena, custom_files[Custom_Default]), arch);
fm_copy_file(fm_str(arena, build_dir, "/custom_4coder" DLL), fm_str(arena, dir, "/custom_4coder" DLL));
char *build_script = fm_str(arena, "buildsuper_", arch_names[arch], BAT);
fm_copy_file(build_script, fm_str(arena, dir, "/buildsuper" BAT));
if (This_OS == Platform_Windows){
fm_copy_folder(arena, cdir, dir, "windows_scripts");
}
fm_copy_folder(arena, cdir, dir, "4coder_API");
fm_copy_folder(arena, cdir, dir, "4coder_lib");
fm_copy_folder(arena, cdir, dir, "4coder_generated");
fm_copy_folder(arena, cdir, dir, "languages");
}
char *dist_name = get_4coder_dist_name(arena, This_OS, tier, arch);
char *zip_name = fm_str(arena, zip_dir, "/", dist_name, ".zip");
fm_make_folder_if_missing(arena, zip_dir);
fm_zip(par_dir, "4coder", zip_name);
}
end_temp(temp);
}
}
int main(int argc, char **argv){
Arena arena = fm_init_system();
char cdir[256];
BEGIN_TIME_SECTION();
i32 n = fm_get_current_directory(cdir, sizeof(cdir));
Assert(n < sizeof(cdir));
END_TIME_SECTION("current directory");
#if defined(DEV_BUILD) || defined(OPT_BUILD) || defined(DEV_BUILD_X86)
u32 flags = DEBUG_INFO | SUPER | INTERNAL;
u32 arch = Arch_X64;
#if defined(OPT_BUILD)
flags |= OPTIMIZATION;
#endif
#if defined(DEV_BUILD_X86)
arch = Arch_X86;
#endif
standard_build(&arena, cdir, flags, arch);
#elif defined(PACKAGE)
package(&arena, cdir);
#else
# error No build type specified.
#endif
return(error_state);
}
// BOTTOM