medfall

A super great game engine
Log | Files | Refs

gen_makefile.lua (9316B)


      1 local function copy( t )
      2 	local res = { }
      3 	for k, v in pairs( t ) do
      4 		res[ k ] = v
      5 	end
      6 	return res
      7 end
      8 
      9 local configs = {
     10 	[ "windows" ] = {
     11 		bin_suffix = ".exe",
     12 		obj_suffix = ".obj",
     13 		lib_suffix = ".lib",
     14 
     15 		toolchain = "msvc",
     16 
     17 		cxxflags = "/I . /c /Oi /Gm- /GR- /EHa- /EHsc /nologo /DNOMINMAX /DWIN32_LEAN_AND_MEAN",
     18 		ldflags = "user32.lib shell32.lib advapi32.lib dbghelp.lib /nologo",
     19 		warnings = "/W4 /wd4100 /wd4146 /wd4189 /wd4201 /wd4324 /wd4351 /wd4127 /wd4505 /wd4530 /wd4702 /D_CRT_SECURE_NO_WARNINGS",
     20 	},
     21 
     22 	[ "windows-64" ] = { },
     23 
     24 	[ "windows-debug" ] = {
     25 		cxxflags = "/Od /MTd /Z7 /Zo",
     26 		ldflags = "/Od /MTd /Z7 /Zo",
     27 	},
     28 	[ "windows-release" ] = {
     29 		cxxflags = "/O2 /MT /DRELEASE_BUILD",
     30 		bin_prefix = "release/",
     31 	},
     32 
     33 	[ "linux" ] = {
     34 		obj_suffix = ".o",
     35 		lib_prefix = "lib",
     36 		lib_suffix = ".a",
     37 
     38 		toolchain = "gcc",
     39 		cxx = "g++",
     40 
     41 		cxxflags = "-I . -c -x c++ -std=c++11 -msse2 -ffast-math -fno-exceptions -fno-rtti -fno-strict-aliasing -fno-strict-overflow -fdiagnostics-color",
     42 		ldflags = "-lm -lpthread -ldl -no-pie",
     43 		warnings = "-Wall -Wextra -Wno-unused-parameter -Wno-unused-function -Wshadow -Wcast-align -Wstrict-overflow -Wvla", -- -Wconversion
     44 	},
     45 
     46 	[ "linux-64" ] = { },
     47 
     48 	[ "linux-debug" ] = {
     49 		cxxflags = "-O0 -ggdb3 -fno-omit-frame-pointer",
     50 	},
     51 	[ "linux-asan" ] = {
     52 		bin_suffix = "-asan",
     53 		cxxflags = "-O0 -ggdb3 -fno-omit-frame-pointer -fsanitize=address",
     54 		ldflags = "-fsanitize=address",
     55 	},
     56 	[ "linux-release" ] = {
     57 		cxxflags = "-O2 -DRELEASE_BUILD",
     58 		ldflags = "-s",
     59 		bin_prefix = "release/",
     60 	},
     61 
     62 	-- TODO: mingw?
     63 }
     64 
     65 configs[ "macos" ] = copy( configs[ "linux" ] )
     66 configs[ "macos" ].cxx = "clang++"
     67 -- TODO: this is not quite right because it can get nuked by gcc_obj_replace_cxxflags
     68 configs[ "macos" ].cxxflags = configs[ "macos" ].cxxflags .. " -mmacosx-version-min=10.9"
     69 configs[ "macos" ].ldflags = "-lm"
     70 
     71 configs[ "macos-64" ] = copy( configs[ "linux-64" ] )
     72 configs[ "macos-debug" ] = copy( configs[ "linux-debug" ] )
     73 configs[ "macos-asan" ] = copy( configs[ "linux-asan" ] )
     74 configs[ "macos-release" ] = copy( configs[ "linux-release" ] )
     75 configs[ "macos-release" ].ldflags = "-Wl,-dead_strip -Wl,-x"
     76 
     77 configs[ "openbsd" ] = copy( configs[ "linux" ] )
     78 configs[ "openbsd" ].cxx = "clang++"
     79 configs[ "openbsd" ].cxxflags = configs[ "openbsd" ].cxxflags .. " -I/usr/local/include"
     80 configs[ "openbsd" ].ldflags = "-lm -lpthread -lexecinfo -L/usr/local/lib"
     81 
     82 configs[ "openbsd-64" ] = copy( configs[ "linux-64" ] )
     83 configs[ "openbsd-debug" ] = copy( configs[ "linux-debug" ] )
     84 
     85 configs[ "openbsd-release" ] = {
     86 	cxxflags = "-O2",
     87 	ldflags = "-s",
     88 }
     89 
     90 local function identify_host()
     91 	local dll_ext = package.cpath:match( "(%a+)$" )
     92 
     93 	if dll_ext == "dll" then
     94 		return "windows", "64"
     95 	end
     96 
     97 	local p = assert( io.popen( "uname -s" ) )
     98 	local uname = assert( p:read( "*all" ) ):gsub( "%s*$", "" )
     99 	assert( p:close() )
    100 
    101 	if uname == "Linux" then
    102 		return "linux", "64"
    103 	end
    104 
    105 	if uname == "Darwin" then
    106 		return "macos", "64"
    107 	end
    108 
    109 	if uname == "OpenBSD" then
    110 		return "openbsd", "64"
    111 	end
    112 
    113 	io.stderr:write( "can't identify host OS" )
    114 	os.exit( 1 )
    115 end
    116 
    117 OS, arch = identify_host()
    118 config = arg[ 1 ] or "debug"
    119 
    120 local double_arch = OS .. "-" .. arch
    121 local double_config = OS .. "-" .. config
    122 local triple = OS .. "-" .. arch .. "-" .. config
    123 
    124 if not configs[ double_arch ] or not configs[ double_config ] then
    125 	io.stderr:write( "bad config: " .. triple .. "\n" )
    126 	os.exit( 1 )
    127 end
    128 
    129 local function concat( key )
    130 	return ""
    131 		.. ( ( configs[ OS ] and configs[ OS ][ key ] ) or "" )
    132 		.. " "
    133 		.. ( ( configs[ double_arch ] and configs[ double_arch ][ key ] ) or "" )
    134 		.. " "
    135 		.. ( ( configs[ double_config ] and configs[ double_config ][ key ] ) or "" )
    136 end
    137 
    138 local function rightmost( key )
    139 	return nil
    140 		or ( configs[ double_config ] and configs[ double_config ][ key ] )
    141 		or ( configs[ double_arch ] and configs[ double_arch ][ key ] )
    142 		or ( configs[ OS ] and configs[ OS ][ key ] )
    143 		or ""
    144 end
    145 
    146 local bin_prefix = rightmost( "bin_prefix" )
    147 local bin_suffix = rightmost( "bin_suffix" )
    148 local obj_suffix = rightmost( "obj_suffix" )
    149 local lib_prefix = rightmost( "lib_prefix" )
    150 local lib_suffix = rightmost( "lib_suffix" )
    151 local cxxflags = concat( "cxxflags" ) .. " " .. concat( "warnings" )
    152 local ldflags = concat( "ldflags" )
    153 
    154 toolchain = rightmost( "toolchain" )
    155 
    156 local dir = "build/" .. triple
    157 local output = { }
    158 
    159 local function join( names, suffix, prefix )
    160 	if not names then
    161 		return ""
    162 	end
    163 
    164 	prefix = prefix or ""
    165 	local res = { }
    166 	for i, name in ipairs( names ) do
    167 		if type( name ) == "table" then
    168 			res[ i ] = join( name, suffix, prefix )
    169 		else
    170 			res[ i ] = dir .. "/" .. prefix .. names[ i ] .. suffix
    171 		end
    172 	end
    173 	return table.concat( res, " " )
    174 end
    175 
    176 local function printh( form, ... )
    177 	print( form:format( ... ) )
    178 end
    179 
    180 local function printf( form, ... )
    181 	table.insert( output, form:format( ... ) )
    182 end
    183 
    184 function bin( bin_name, objs, libs )
    185 	assert( type( objs ) == "table", "objs should be a table" )
    186 	assert( not libs or type( libs ) == "table", "libs should be a table or nil" )
    187 	local bin_path = ( "%s%s%s" ):format( bin_prefix, bin_name, bin_suffix )
    188 	printh( "BINS += %s", bin_path )
    189 	printf( "%s: %s %s", bin_path, join( objs, obj_suffix ), join( libs, lib_suffix, lib_prefix ) )
    190 	printf( "clean::\n\trm -f %s", bin_path )
    191 end
    192 
    193 function lib( lib_name, objs )
    194 	assert( type( objs ) == "table", "objs should be a table" )
    195 	printf( "%s/%s%s%s: %s", dir, lib_prefix, lib_name, lib_suffix, join( objs, obj_suffix ) )
    196 end
    197 
    198 function rc( rc_name )
    199 	if OS == "windows" then
    200 		printf( "%s/%s%s: %s.rc %s.xml", dir, rc_name, obj_suffix, rc_name, rc_name )
    201 		printf( "\t@printf \"\\033[1;33mbuilding $@\\033[0m\\n\"" )
    202 		printf( "\t@mkdir -p \"$(@D)\"" )
    203 		printf( "\t@rc /fo$@ /nologo $<" )
    204 	else
    205 		local cxx = rightmost( "cxx" )
    206 		printf( "%s/%s%s:", dir, rc_name, obj_suffix )
    207 		printf( "\t@printf \"\\033[1;33mbuilding $@\\033[0m\\n\"" )
    208 		printf( "\t@mkdir -p \"$(@D)\"" )
    209 		printf( "\t@%s -c -x c++ /dev/null -o $@", cxx )
    210 	end
    211 end
    212 
    213 function bin_ldflags( bin_name, ldflags )
    214 	local bin_path = ( "%s%s%s" ):format( bin_prefix, bin_name, bin_suffix )
    215 	printf( "%s: LDFLAGS += %s", bin_path, ldflags )
    216 end
    217 
    218 function obj_cxxflags( obj_name, cxxflags )
    219 	printf( "%s/%s%s: CXXFLAGS += %s", dir, obj_name, obj_suffix, cxxflags )
    220 end
    221 
    222 function obj_replace_cxxflags( obj_name, cxxflags )
    223 	printf( "%s/%s%s: CXXFLAGS := %s", dir, obj_name, obj_suffix, cxxflags )
    224 end
    225 
    226 local function toolchain_helper( t, f )
    227 	return function( ... )
    228 		if toolchain == t then
    229 			f( ... )
    230 		end
    231 	end
    232 end
    233 
    234 msvc_bin_ldflags = toolchain_helper( "msvc", bin_ldflags )
    235 msvc_obj_cxxflags = toolchain_helper( "msvc", obj_cxxflags )
    236 msvc_obj_replace_cxxflags = toolchain_helper( "msvc", obj_replace_cxxflags )
    237 
    238 gcc_bin_ldflags = toolchain_helper( "gcc", bin_ldflags )
    239 gcc_obj_cxxflags = toolchain_helper( "gcc", obj_cxxflags )
    240 gcc_obj_replace_cxxflags = toolchain_helper( "gcc", obj_replace_cxxflags )
    241 
    242 printf( "CXXFLAGS := %s", cxxflags )
    243 printf( "LDFLAGS := %s", ldflags )
    244 printf( "MAKEFLAGS += -r" )
    245 
    246 printf( "" )
    247 printf( "all: $(BINS)" )
    248 printf( "" )
    249 
    250 if toolchain == "msvc" then
    251 
    252 printf( [[
    253 VC = ${ProgramFiles(x86)}\Microsoft Visual Studio 14.0\VC
    254 KIT81 = ${ProgramFiles(x86)}\Windows Kits\8.1
    255 KIT10 = ${ProgramFiles(x86)}\Windows Kits\10
    256 DX = ${ProgramFiles(x86)}\Microsoft DirectX SDK (June 2010)
    257 
    258 export INCLUDE := $(VC)\include;$(KIT10)\Include\10.0.10240.0\ucrt;$(KIT81)\Include\shared;$(DX)\Include;$(KIT81)\Include\um;$(KIT81)\Include\winrt
    259 export LIB := $(VC)\lib\amd64;$(KIT10)\Lib\10.0.10240.0\ucrt\x64;$(KIT81)\lib\winv6.3\um\x64
    260 export PATH := /cygdrive/c/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/amd64/:/cygdrive/c/Program Files (x86)/Windows Kits/8.1/bin/x64/:$(PATH)
    261 ]] )
    262 
    263 printf( [[
    264 $(BINS): %%:
    265 	@printf "\033[1;31mbuilding $@\033[0m\n"
    266 	@mkdir -p "$(@D)"
    267 	@cl -Fe$@ $^ $(LDFLAGS)
    268 ]] )
    269 printf( [[
    270 %s/%%%s: %%.cc
    271 	@printf "\033[1;32mbuilding $<\033[0m\n"
    272 	@mkdir -p "$(@D)"
    273 	@cl $(CXXFLAGS) -Fo$@ $^
    274 ]], dir, obj_suffix )
    275 printf( [[
    276 $(OBJS): %%:
    277 	@printf "\033[1;32mbuilding $<\033[0m\n"
    278 	@mkdir -p "$(@D)"
    279 	@cl $(CXXFLAGS) -Fo$@ -Tp$<
    280 ]] )
    281 printf( [[
    282 %%%s:
    283 	@printf "\033[1;35mbuilding $@\033[0m\n"
    284 	@mkdir -p "$(@D)"
    285 	@lib -OUT:$@ $^
    286 ]], lib_suffix )
    287 
    288 elseif toolchain == "gcc" then
    289 
    290 local cxx = rightmost( "cxx" )
    291 
    292 printf( [[
    293 $(BINS): %%:
    294 	@env printf "\033[1;31mbuilding $@\033[0m\n"
    295 	@mkdir -p "$(@D)"
    296 	@%s -o $@ $^ $(LDFLAGS)
    297 ]], cxx )
    298 printf( [[
    299 %s/%%%s: %%.cc
    300 	@env printf "\033[1;32mbuilding $<\033[0m\n"
    301 	@mkdir -p "$(@D)"
    302 	@%s $(CXXFLAGS) -o $@ $< -MMD -MP
    303 ]], dir, obj_suffix, cxx )
    304 printf( [[
    305 $(OBJS): %%:
    306 	@env printf "\033[1;32mbuilding $<\033[0m\n"
    307 	@mkdir -p "$(@D)"
    308 	@%s $(CXXFLAGS) -o $@ $< -MMD -MP
    309 ]], cxx )
    310 printf( [[
    311 %%%s:
    312 	@env printf "\033[1;35mbuilding $@\033[0m\n"
    313 	@mkdir -p "$(@D)"
    314 	@$(AR) rs $@ $^
    315 ]], lib_suffix )
    316 
    317 -- you can't -include %s/**.d, so let's hardcode 6 levels and hope that's enough
    318 printf( "-include %s/*.d", dir )
    319 printf( "-include %s/*/*.d", dir )
    320 printf( "-include %s/*/*/*.d", dir )
    321 printf( "-include %s/*/*/*/*.d", dir )
    322 printf( "-include %s/*/*/*/*/*.d", dir )
    323 printf( "-include %s/*/*/*/*/*/*.d", dir )
    324 
    325 end
    326 
    327 printf( "clean::\n\trm -rf build release" )
    328 
    329 automatically_print_output_at_exit = setmetatable( { }, {
    330 	__gc = function()
    331 		print( table.concat( output, "\n" ) )
    332 	end
    333 } )