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 } )