builder: replace single `goto start` usage, with `for { ... continue ... break}`

pull/7079/head
Delyan Angelov 2020-12-01 22:10:02 +02:00
parent c5cd53ca79
commit 394e9c4c56
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
1 changed files with 326 additions and 324 deletions

View File

@ -225,357 +225,359 @@ fn (mut v Builder) cc() {
// //
mut tried_compilation_commands := []string{} mut tried_compilation_commands := []string{}
original_pwd := os.getwd() original_pwd := os.getwd()
// TODO remove the start: goto start construct; for {
// use a labeled for break instead // try to compile with the choosen compiler
start: // if compilation fails, retry again with another
mut ccompiler := v.pref.ccompiler mut ccompiler := v.pref.ccompiler
$if windows { $if windows {
if ccompiler == 'msvc' { if ccompiler == 'msvc' {
v.cc_msvc() v.cc_msvc()
return return
}
} }
} if v.pref.os == .ios {
if v.pref.os == .ios { ios_sdk := if v.pref.is_ios_simulator { 'iphonesimulator' } else { 'iphoneos' }
ios_sdk := if v.pref.is_ios_simulator { 'iphonesimulator' } else { 'iphoneos' } ios_sdk_path_res := os.exec('xcrun --sdk $ios_sdk --show-sdk-path') or {
ios_sdk_path_res := os.exec('xcrun --sdk $ios_sdk --show-sdk-path') or { panic("Couldn\'t find iphonesimulator")
panic("Couldn\'t find iphonesimulator") }
mut isysroot := ios_sdk_path_res.output.replace('\n', '')
ccompiler = 'xcrun --sdk iphoneos clang -isysroot $isysroot'
} }
mut isysroot := ios_sdk_path_res.output.replace('\n', '') // arguments for the C compiler
ccompiler = 'xcrun --sdk iphoneos clang -isysroot $isysroot' // TODO : activate -Werror once no warnings remain
} // '-Werror',
// arguments for the C compiler // TODO : try and remove the below workaround options when the corresponding
// TODO : activate -Werror once no warnings remain // warnings are totally fixed/removed
// '-Werror', mut args := [v.pref.cflags, '-std=gnu99', '-Wall', '-Wextra', '-Wno-unused-variable', '-Wno-unused-parameter',
// TODO : try and remove the below workaround options when the corresponding '-Wno-unused-result', '-Wno-unused-function', '-Wno-missing-braces', '-Wno-unused-label']
// warnings are totally fixed/removed if v.pref.os == .ios {
mut args := [v.pref.cflags, '-std=gnu99', '-Wall', '-Wextra', '-Wno-unused-variable', '-Wno-unused-parameter', args << '-framework Foundation'
'-Wno-unused-result', '-Wno-unused-function', '-Wno-missing-braces', '-Wno-unused-label'] args << '-framework UIKit'
if v.pref.os == .ios { args << '-framework Metal'
args << '-framework Foundation' args << '-framework MetalKit'
args << '-framework UIKit' args << '-DSOKOL_METAL'
args << '-framework Metal' args << '-fobjc-arc'
args << '-framework MetalKit'
args << '-DSOKOL_METAL'
args << '-fobjc-arc'
}
mut linker_flags := []string{}
if !v.pref.is_shared && v.pref.build_mode != .build_module && os.user_os() == 'windows' &&
!v.pref.out_name.ends_with('.exe') {
v.pref.out_name += '.exe'
}
// linux_host := os.user_os() == 'linux'
v.log('cc() isprod=$v.pref.is_prod outname=$v.pref.out_name')
if v.pref.is_shared {
linker_flags << '-shared'
args << '-fPIC' // -Wl,-z,defs'
$if macos {
v.pref.out_name += '.dylib'
} $else $if windows {
v.pref.out_name += '.dll'
} $else {
v.pref.out_name += '.so'
} }
} mut linker_flags := []string{}
if v.pref.is_bare { if !v.pref.is_shared && v.pref.build_mode != .build_module && os.user_os() == 'windows' &&
args << '-fno-stack-protector' !v.pref.out_name.ends_with('.exe') {
args << '-ffreestanding' v.pref.out_name += '.exe'
linker_flags << '-static' }
linker_flags << '-nostdlib' // linux_host := os.user_os() == 'linux'
} v.log('cc() isprod=$v.pref.is_prod outname=$v.pref.out_name')
if v.pref.build_mode == .build_module { if v.pref.is_shared {
v.pref.out_name = v.pref.cache_manager.postfix_with_key2cpath('.o', v.pref.path) // v.out_name linker_flags << '-shared'
println('Building $v.pref.path to $v.pref.out_name ...') args << '-fPIC' // -Wl,-z,defs'
v.pref.cache_manager.save('.description.txt', v.pref.path, '${v.pref.path:-30} @ $v.pref.cache_manager.vopts\n') $if macos {
// println('v.table.imports:') v.pref.out_name += '.dylib'
// println(v.table.imports) } $else $if windows {
} v.pref.out_name += '.dll'
debug_mode := v.pref.is_debug } $else {
mut debug_options := '-g3' v.pref.out_name += '.so'
mut optimization_options := '-O2' }
mut guessed_compiler := v.pref.ccompiler }
if guessed_compiler == 'cc' && v.pref.is_prod { if v.pref.is_bare {
// deliberately guessing only for -prod builds for performance reasons args << '-fno-stack-protector'
if ccversion := os.exec('cc --version') { args << '-ffreestanding'
if ccversion.exit_code == 0 { linker_flags << '-static'
if ccversion.output.contains('This is free software;') && linker_flags << '-nostdlib'
ccversion.output.contains('Free Software Foundation, Inc.') { }
guessed_compiler = 'gcc' if v.pref.build_mode == .build_module {
} v.pref.out_name = v.pref.cache_manager.postfix_with_key2cpath('.o', v.pref.path) // v.out_name
if ccversion.output.contains('clang version ') { println('Building $v.pref.path to $v.pref.out_name ...')
guessed_compiler = 'clang' v.pref.cache_manager.save('.description.txt', v.pref.path, '${v.pref.path:-30} @ $v.pref.cache_manager.vopts\n')
// println('v.table.imports:')
// println(v.table.imports)
}
debug_mode := v.pref.is_debug
mut debug_options := '-g3'
mut optimization_options := '-O2'
mut guessed_compiler := v.pref.ccompiler
if guessed_compiler == 'cc' && v.pref.is_prod {
// deliberately guessing only for -prod builds for performance reasons
if ccversion := os.exec('cc --version') {
if ccversion.exit_code == 0 {
if ccversion.output.contains('This is free software;') &&
ccversion.output.contains('Free Software Foundation, Inc.') {
guessed_compiler = 'gcc'
}
if ccversion.output.contains('clang version ') {
guessed_compiler = 'clang'
}
} }
} }
} }
} //
// is_cc_tcc := ccompiler.contains('tcc') || guessed_compiler == 'tcc'
is_cc_tcc := ccompiler.contains('tcc') || guessed_compiler == 'tcc' is_cc_clang := !is_cc_tcc && (ccompiler.contains('clang') || guessed_compiler == 'clang')
is_cc_clang := !is_cc_tcc && (ccompiler.contains('clang') || guessed_compiler == 'clang') is_cc_gcc := !is_cc_tcc && !is_cc_clang &&
is_cc_gcc := !is_cc_tcc && !is_cc_clang && (ccompiler.contains('gcc') || guessed_compiler == 'gcc')
(ccompiler.contains('gcc') || guessed_compiler == 'gcc') // is_cc_msvc := v.pref.ccompiler.contains('msvc') || guessed_compiler == 'msvc'
// is_cc_msvc := v.pref.ccompiler.contains('msvc') || guessed_compiler == 'msvc' //
// if is_cc_clang {
if is_cc_clang { if debug_mode {
debug_options = '-g3 -O0'
}
optimization_options = '-O3'
mut have_flto := true
$if openbsd {
have_flto = false
}
if have_flto {
optimization_options += ' -flto'
}
}
if is_cc_gcc {
if debug_mode {
debug_options = '-g3 -no-pie'
}
optimization_options = '-O3 -fno-strict-aliasing -flto'
}
if debug_mode { if debug_mode {
debug_options = '-g3 -O0' args << debug_options
// $if macos {
// args << ' -ferror-limit=5000 '
// }
} }
optimization_options = '-O3' if v.pref.is_prod {
mut have_flto := true args << optimization_options
$if openbsd {
have_flto = false
} }
if have_flto { if v.pref.is_prod && !debug_mode {
optimization_options += ' -flto' // sokol and other C libraries that use asserts
// have much better performance when NDEBUG is defined
// See also http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
args << '-DNDEBUG'
} }
} if debug_mode && os.user_os() != 'windows' {
if is_cc_gcc { linker_flags << ' -rdynamic ' // needed for nicer symbolic backtraces
if debug_mode {
debug_options = '-g3 -no-pie'
} }
optimization_options = '-O3 -fno-strict-aliasing -flto' if ccompiler != 'msvc' && v.pref.os != .freebsd {
} args << '-Werror=implicit-function-declaration'
if debug_mode {
args << debug_options
// $if macos {
// args << ' -ferror-limit=5000 '
// }
}
if v.pref.is_prod {
args << optimization_options
}
if v.pref.is_prod && !debug_mode {
// sokol and other C libraries that use asserts
// have much better performance when NDEBUG is defined
// See also http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
args << '-DNDEBUG'
}
if debug_mode && os.user_os() != 'windows' {
linker_flags << ' -rdynamic ' // needed for nicer symbolic backtraces
}
if ccompiler != 'msvc' && v.pref.os != .freebsd {
args << '-Werror=implicit-function-declaration'
}
if v.pref.is_liveshared || v.pref.is_livemain {
if v.pref.os == .linux || os.user_os() == 'linux' {
linker_flags << '-rdynamic'
} }
if v.pref.os == .macos || os.user_os() == 'macos' { if v.pref.is_liveshared || v.pref.is_livemain {
args << '-flat_namespace' if v.pref.os == .linux || os.user_os() == 'linux' {
} linker_flags << '-rdynamic'
} }
mut libs := '' // builtin.o os.o http.o etc if v.pref.os == .macos || os.user_os() == 'macos' {
if v.pref.build_mode == .build_module { args << '-flat_namespace'
args << '-c'
} else if v.pref.use_cache {
mut built_modules := []string{}
builtin_obj_path := v.rebuild_cached_module(vexe, 'vlib/builtin')
libs += ' ' + builtin_obj_path
for ast_file in v.parsed_files {
for imp_stmt in ast_file.imports {
imp := imp_stmt.mod
if imp in built_modules {
continue
}
// not working
if imp == 'webview' {
continue
}
// println('cache: import "$imp"')
mod_path := imp.replace('.', os.path_separator)
// TODO: to get import path all imports (even relative) we can use:
// import_path := v.find_module_path(imp, ast_file.path) or {
// verror('cannot import module "$imp" (not found)')
// break
// }
// The problem is cmd/v is in module main and imports
// the relative module named help, which is built as cmd.v.help not help
// currently this got this workign by building into main, see ast.FnDecl in cgen
if imp == 'help' {
continue
}
// we are skipping help manually above, this code will skip all relative imports
// if os.is_dir(af_base_dir + os.path_separator + mod_path) {
// continue
// }
imp_path := os.join_path('vlib', mod_path)
obj_path := v.rebuild_cached_module(vexe, imp_path)
libs += ' ' + obj_path
if obj_path.ends_with('vlib/ui.o') {
args << '-framework Cocoa -framework Carbon'
}
built_modules << imp
} }
} }
} mut libs := '' // builtin.o os.o http.o etc
if v.pref.sanitize { if v.pref.build_mode == .build_module {
args << '-fsanitize=leak' args << '-c'
} } else if v.pref.use_cache {
// Cross compiling for linux mut built_modules := []string{}
if v.pref.os == .linux { builtin_obj_path := v.rebuild_cached_module(vexe, 'vlib/builtin')
$if !linux { libs += ' ' + builtin_obj_path
v.cc_linux_cross() for ast_file in v.parsed_files {
return for imp_stmt in ast_file.imports {
} imp := imp_stmt.mod
} if imp in built_modules {
// Cross compiling windows continue
// }
// Output executable name // not working
if v.pref.os == .ios { if imp == 'webview' {
bundle_name := v.pref.out_name.split('/').last() continue
args << '-o "${v.pref.out_name}.app/$bundle_name"' }
} else { // println('cache: import "$imp"')
args << '-o "$v.pref.out_name"' mod_path := imp.replace('.', os.path_separator)
} // TODO: to get import path all imports (even relative) we can use:
if os.is_dir(v.pref.out_name) { // import_path := v.find_module_path(imp, ast_file.path) or {
verror("'$v.pref.out_name' is a directory") // verror('cannot import module "$imp" (not found)')
} // break
// macOS code can include objective C TODO remove once objective C is replaced with C // }
if v.pref.os == .macos || v.pref.os == .ios { // The problem is cmd/v is in module main and imports
if !is_cc_tcc { // the relative module named help, which is built as cmd.v.help not help
args << '-x objective-c' // currently this got this workign by building into main, see ast.FnDecl in cgen
} if imp == 'help' {
} continue
// The C file we are compiling }
args << '"$v.out_name_c"' // we are skipping help manually above, this code will skip all relative imports
if v.pref.os == .macos { // if os.is_dir(af_base_dir + os.path_separator + mod_path) {
args << '-x none' // continue
} // }
// Min macos version is mandatory I think? imp_path := os.join_path('vlib', mod_path)
if v.pref.os == .macos { obj_path := v.rebuild_cached_module(vexe, imp_path)
args << '-mmacosx-version-min=10.7' libs += ' ' + obj_path
} if obj_path.ends_with('vlib/ui.o') {
if v.pref.os == .ios { args << '-framework Cocoa -framework Carbon'
args << '-miphoneos-version-min=10.0' }
} built_modules << imp
if v.pref.os == .windows { }
args << '-municode'
}
cflags := v.get_os_cflags()
// add .o files
args << cflags.c_options_only_object_files()
// add all flags (-I -l -L etc) not .o files
args << cflags.c_options_without_object_files()
args << libs
// For C++ we must be very tolerant
if guessed_compiler.contains('++') {
args << '-fpermissive'
args << '-w'
}
// TODO: why is this duplicated from above?
if v.pref.use_cache {
// vexe := pref.vexe_path()
// cached_modules := ['builtin', 'os', 'math', 'strconv', 'strings', 'hash'], // , 'strconv.ftoa']
// for cfile in cached_modules {
// ofile := os.join_path(pref.default_module_path, 'cache', 'vlib', cfile.replace('.', '/') +
// '.o')
// if !os.exists(ofile) {
// println('${cfile}.o is missing. Building...')
// println('$vexe build-module vlib/$cfile')
// os.system('$vexe build-module vlib/$cfile')
// }
// args << ofile
// }
if !is_cc_tcc {
$if linux {
linker_flags << '-Xlinker -z'
linker_flags << '-Xlinker muldefs'
} }
} }
} if v.pref.sanitize {
if is_cc_tcc && 'no_backtrace' !in v.pref.compile_defines { args << '-fsanitize=leak'
args << '-bt25' }
} // Cross compiling for linux
// Without these libs compilation will fail on Linux
// || os.user_os() == 'linux'
if !v.pref.is_bare && v.pref.build_mode != .build_module && v.pref.os in
[.linux, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .haiku] {
linker_flags << '-lm'
linker_flags << '-lpthread'
// -ldl is a Linux only thing. BSDs have it in libc.
if v.pref.os == .linux { if v.pref.os == .linux {
linker_flags << '-ldl' $if !linux {
v.cc_linux_cross()
return
}
} }
if v.pref.os == .freebsd { // Cross compiling windows
// FreeBSD: backtrace needs execinfo library while linking //
linker_flags << '-lexecinfo' // Output executable name
if v.pref.os == .ios {
bundle_name := v.pref.out_name.split('/').last()
args << '-o "${v.pref.out_name}.app/$bundle_name"'
} else {
args << '-o "$v.pref.out_name"'
} }
} if os.is_dir(v.pref.out_name) {
if !v.pref.is_bare && v.pref.os == .js && os.user_os() == 'linux' { verror("'$v.pref.out_name' is a directory")
linker_flags << '-lm' }
} // macOS code can include objective C TODO remove once objective C is replaced with C
env_cflags := os.getenv('CFLAGS') if v.pref.os == .macos || v.pref.os == .ios {
env_ldflags := os.getenv('LDFLAGS') if !is_cc_tcc {
str_args := env_cflags + ' ' + args.join(' ') + ' ' + linker_flags.join(' ') + ' ' + env_ldflags args << '-x objective-c'
if v.pref.is_verbose { }
println('cc args=$str_args') }
println(args) // The C file we are compiling
} args << '"$v.out_name_c"'
// write args to response file if v.pref.os == .macos {
response_file := '${v.out_name_c}.rsp' args << '-x none'
response_file_content := str_args.replace('\\', '\\\\') }
os.write_file(response_file, response_file_content) or { // Min macos version is mandatory I think?
verror('Unable to write response file "$response_file"') if v.pref.os == .macos {
} args << '-mmacosx-version-min=10.7'
if !debug_mode { }
v.pref.cleanup_files << v.out_name_c if v.pref.os == .ios {
v.pref.cleanup_files << response_file args << '-miphoneos-version-min=10.0'
} }
// if v.pref.os == .windows {
todo() args << '-municode'
os.chdir(vdir) }
cmd := '$ccompiler @$response_file' cflags := v.get_os_cflags()
tried_compilation_commands << cmd // add .o files
v.show_cc(cmd, response_file, response_file_content) args << cflags.c_options_only_object_files()
// Run // add all flags (-I -l -L etc) not .o files
ticks := time.ticks() args << cflags.c_options_without_object_files()
res := os.exec(cmd) or { args << libs
// C compilation failed. // For C++ we must be very tolerant
// If we are on Windows, try msvc if guessed_compiler.contains('++') {
println('C compilation failed.') args << '-fpermissive'
os.chdir(original_pwd) args << '-w'
/* }
if os.user_os() == 'windows' && v.pref.ccompiler != 'msvc' { // TODO: why is this duplicated from above?
if v.pref.use_cache {
// vexe := pref.vexe_path()
// cached_modules := ['builtin', 'os', 'math', 'strconv', 'strings', 'hash'], // , 'strconv.ftoa']
// for cfile in cached_modules {
// ofile := os.join_path(pref.default_module_path, 'cache', 'vlib', cfile.replace('.', '/') +
// '.o')
// if !os.exists(ofile) {
// println('${cfile}.o is missing. Building...')
// println('$vexe build-module vlib/$cfile')
// os.system('$vexe build-module vlib/$cfile')
// }
// args << ofile
// }
if !is_cc_tcc {
$if linux {
linker_flags << '-Xlinker -z'
linker_flags << '-Xlinker muldefs'
}
}
}
if is_cc_tcc && 'no_backtrace' !in v.pref.compile_defines {
args << '-bt25'
}
// Without these libs compilation will fail on Linux
// || os.user_os() == 'linux'
if !v.pref.is_bare && v.pref.build_mode != .build_module && v.pref.os in
[.linux, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .haiku] {
linker_flags << '-lm'
linker_flags << '-lpthread'
// -ldl is a Linux only thing. BSDs have it in libc.
if v.pref.os == .linux {
linker_flags << '-ldl'
}
if v.pref.os == .freebsd {
// FreeBSD: backtrace needs execinfo library while linking
linker_flags << '-lexecinfo'
}
}
if !v.pref.is_bare && v.pref.os == .js && os.user_os() == 'linux' {
linker_flags << '-lm'
}
env_cflags := os.getenv('CFLAGS')
env_ldflags := os.getenv('LDFLAGS')
str_args := env_cflags + ' ' + args.join(' ') + ' ' + linker_flags.join(' ') + ' ' + env_ldflags
if v.pref.is_verbose {
println('cc args=$str_args')
println(args)
}
// write args to response file
response_file := '${v.out_name_c}.rsp'
response_file_content := str_args.replace('\\', '\\\\')
os.write_file(response_file, response_file_content) or {
verror('Unable to write response file "$response_file"')
}
if !debug_mode {
v.pref.cleanup_files << v.out_name_c
v.pref.cleanup_files << response_file
}
//
todo()
os.chdir(vdir)
cmd := '$ccompiler @$response_file'
tried_compilation_commands << cmd
v.show_cc(cmd, response_file, response_file_content)
// Run
ticks := time.ticks()
res := os.exec(cmd) or {
// C compilation failed.
// If we are on Windows, try msvc
println('C compilation failed.')
os.chdir(original_pwd)
/*
if os.user_os() == 'windows' && v.pref.ccompiler != 'msvc' {
println('Trying to build with MSVC') println('Trying to build with MSVC')
v.cc_msvc() v.cc_msvc()
return return
} }
*/ */
verror(err) verror(err)
return return
} }
diff := time.ticks() - ticks diff := time.ticks() - ticks
v.timing_message('C ${ccompiler:3}', diff) v.timing_message('C ${ccompiler:3}', diff)
if v.pref.show_c_output { if v.pref.show_c_output {
v.show_c_compiler_output(res) v.show_c_compiler_output(res)
} }
os.chdir(original_pwd) os.chdir(original_pwd)
if res.exit_code != 0 { if res.exit_code != 0 {
if ccompiler.contains('tcc.exe') { if ccompiler.contains('tcc.exe') {
// a TCC problem? Retry with the system cc: // a TCC problem? Retry with the system cc:
if tried_compilation_commands.len > 1 { if tried_compilation_commands.len > 1 {
eprintln('Recompilation loop detected (ccompiler: $ccompiler):') eprintln('Recompilation loop detected (ccompiler: $ccompiler):')
for recompile_command in tried_compilation_commands { for recompile_command in tried_compilation_commands {
eprintln(' $recompile_command') eprintln(' $recompile_command')
}
exit(101)
} }
exit(101) eprintln('recompilation with tcc failed; retrying with cc ...')
v.pref.ccompiler = pref.default_c_compiler()
continue
}
if res.exit_code == 127 {
verror('C compiler error, while attempting to run: \n' +
'-----------------------------------------------------------\n' + '$cmd\n' +
'-----------------------------------------------------------\n' + 'Probably your C compiler is missing. \n' +
'Please reinstall it, or make it available in your PATH.\n\n' + missing_compiler_info())
} }
eprintln('recompilation with tcc failed; retrying with cc ...')
v.pref.ccompiler = pref.default_c_compiler()
goto start
} }
if res.exit_code == 127 { if !v.pref.show_c_output {
verror('C compiler error, while attempting to run: \n' + v.post_process_c_compiler_output(res)
'-----------------------------------------------------------\n' + '$cmd\n' +
'-----------------------------------------------------------\n' + 'Probably your C compiler is missing. \n' +
'Please reinstall it, or make it available in your PATH.\n\n' + missing_compiler_info())
} }
} // Print the C command
if !v.pref.show_c_output { if v.pref.is_verbose {
v.post_process_c_compiler_output(res) println('$ccompiler took $diff ms')
} println('=========\n')
// Print the C command }
if v.pref.is_verbose { break
println('$ccompiler took $diff ms')
println('=========\n')
} }
// Link it if we are cross compiling and need an executable // Link it if we are cross compiling and need an executable
/* /*