Browse Source

More flexible control over debug/runtime flag selection

default_compile_flags
vector-of-bool 4 years ago
parent
commit
e259992656
3 changed files with 166 additions and 36 deletions
  1. +30
    -3
      res/toolchain-schema.json
  2. +92
    -30
      src/dds/toolchain/from_json.cpp
  3. +44
    -3
      src/dds/toolchain/from_json.test.cpp

+ 30
- 3
res/toolchain-schema.json View File

"patternProperties": { "patternProperties": {
"^\\$": {} "^\\$": {}
}, },
"$schema": "https://json-schema.org/draft/2019-09/schema",
"definitions": { "definitions": {
"command_line_flags": { "command_line_flags": {
"anyOf": [ "anyOf": [
"$ref": "#/definitions/command_line_flags" "$ref": "#/definitions/command_line_flags"
}, },
"debug": { "debug": {
"description": "Enable the generation of debug information",
"type": "boolean",
"default": true
"description": "Tweak the generation of debug information",
"default": true,
"oneOf": [
{
"type": "string",
"enum": [
"embedded",
"split"
]
},
{
"type": "boolean"
}
]
}, },
"optimize": { "optimize": {
"description": "Optimize generated code", "description": "Optimize generated code",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, },
"runtime": {
"description": "Select the runtime/stdlib modes",
"type": "object",
"additionalProperties": false,
"properties": {
"static": {
"type": "boolean",
"description": "If `true`, enable static stdlib/runtime linking"
},
"debug": {
"type": "boolean",
"description": "If 'true', enable debug for the stdlib/runtime"
}
}
},
"advanced": { "advanced": {
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,

+ 92
- 30
src/dds/toolchain/from_json.cpp View File

opt_string_seq link_flags; opt_string_seq link_flags;
opt_string_seq warning_flags; opt_string_seq warning_flags;


optional<bool> do_debug;
optional<bool> debug_bool;
opt_string debug_str;
optional<bool> do_optimize; optional<bool> do_optimize;
optional<bool> runtime_static;
optional<bool> runtime_debug;


// Advanced-mode: // Advanced-mode:
opt_string deps_mode_str; opt_string deps_mode_str;
KEY_EXTEND_FLAGS(link_flags), KEY_EXTEND_FLAGS(link_flags),
KEY_EXTEND_FLAGS(compiler_launcher), KEY_EXTEND_FLAGS(compiler_launcher),
if_key{"debug", if_key{"debug",
require_type<bool>("`debug` must be a boolean value"),
put_into{do_debug}},
if_type<bool>(put_into{debug_bool}),
if_type<std::string>(put_into{debug_str}),
reject_with{"'debug' must be a bool or string"}},
if_key{"optimize", if_key{"optimize",
require_type<bool>("`optimize` must be a boolean value"), require_type<bool>("`optimize` must be a boolean value"),
put_into{do_optimize}}, put_into{do_optimize}},
if_key{"flags", extend_flags("flags", common_flags)}, if_key{"flags", extend_flags("flags", common_flags)},
if_key{"runtime",
require_type<json5::data::mapping_type>("'runtime' must be a JSON object"),
mapping{if_key{"static",
require_type<bool>("'/runtime/static' should be a boolean"),
put_into(runtime_static)},
if_key{"debug",
require_type<bool>("'/runtime/debug' should be a boolean"),
put_into(runtime_debug)},
[](auto&& key, auto&&) {
fail("Unknown 'runtime' key '{}'", key);
return dc_reject_t();
}}},
if_key{ if_key{
"advanced", "advanced",
require_type<json5::data::mapping_type>("`advanced` must be a mapping"), require_type<json5::data::mapping_type>("`advanced` must be a mapping"),
"flags", "flags",
"debug", "debug",
"optimize", "optimize",
"runtime",
}); });
fail(context, fail(context,
"Unknown toolchain config key ‘{}’ (Did you mean ‘{}’?)", "Unknown toolchain config key ‘{}’ (Did you mean ‘{}’?)",
fail(context, rej_opt->message); fail(context, rej_opt->message);
} }


if (debug_str.has_value() && debug_str != "embedded" && debug_str != "split"
&& debug_str != "none") {
fail(context, "'debug' string must be one of 'none', 'embedded', or 'split'");
}

enum compiler_id_e_t { enum compiler_id_e_t {
no_comp_id, no_comp_id,
msvc, msvc,
return cxx_ver_iter->second; return cxx_ver_iter->second;
}; };


auto get_link_flags = [&]() -> string_seq {
auto get_runtime_flags = [&]() -> string_seq {
string_seq ret; string_seq ret;
if (is_msvc) { if (is_msvc) {
strv rt_lib = "/MT";
if (do_optimize.value_or(false)) {
extend(ret, {"/O2"});
std::string rt_flag = "/M";
// Select debug/release runtime flag. Default is 'true'
if (runtime_static.value_or(true)) {
rt_flag.push_back('T');
} else {
rt_flag.push_back('D');
} }
if (do_debug.value_or(false)) {
extend(ret, {"/Z7", "/DEBUG"});
rt_lib = "/MTd";
if (runtime_debug.value_or(debug_bool.value_or(false) || debug_str == "embedded"
|| debug_str == "split")) {
rt_flag.push_back('d');
} }
ret.emplace_back(rt_lib);
ret.push_back(rt_flag);
} else if (is_gnu_like) { } else if (is_gnu_like) {
if (do_optimize.value_or(false)) {
extend(ret, {"-O2"});
if (runtime_static.value_or(false)) {
extend(ret, {"-static-libgcc", "-static-libstdc++"});
} }
if (do_debug.value_or(false)) {
extend(ret, {"-g"});
if (runtime_debug.value_or(false)) {
extend(ret, {"-D_GLIBCXX_DEBUG"});
} }
} else {
// No flags if we don't know the compiler
}

return ret;
};

auto get_optim_flags = [&]() -> string_seq {
if (do_optimize != true) {
return {};
} }
if (is_msvc) {
return {"/O2"};
} else if (is_gnu_like) {
return {"-O2"};
} else {
return {};
}
};

auto get_debug_flags = [&]() -> string_seq {
if (is_msvc) {
if (debug_bool == true || debug_str == "embedded") {
return {"/Z7"};
} else if (debug_str == "split") {
return {"/Zi"};
} else {
// Do not generate any debug infro
return {};
}
} else if (is_gnu_like) {
if (debug_bool == true || debug_str == "embedded") {
return {"-g"};
} else if (debug_str == "split") {
return {"-g", "-gsplit-dwarf"};
} else {
// Do not generate debug info
return {};
}
} else {
// Cannont deduce the debug flags
return {};
}
};

auto get_link_flags = [&]() -> string_seq {
string_seq ret;
extend(ret, get_runtime_flags());
extend(ret, get_optim_flags());
extend(ret, get_debug_flags());
if (link_flags) { if (link_flags) {
extend(ret, *link_flags); extend(ret, *link_flags);
} }


auto get_flags = [&](language lang) -> string_seq { auto get_flags = [&](language lang) -> string_seq {
string_seq ret; string_seq ret;
extend(ret, get_runtime_flags());
extend(ret, get_optim_flags());
extend(ret, get_debug_flags());
if (is_msvc) { if (is_msvc) {
strv rt_lib = "/MT";
if (do_optimize.has_value() && *do_optimize) {
extend(ret, {"/O2"});
}
if (do_debug.has_value() && *do_debug) {
extend(ret, {"/Z7", "/DEBUG"});
rt_lib = "/MTd";
}
ret.emplace_back(rt_lib);
if (lang == language::cxx) { if (lang == language::cxx) {
extend(ret, {"/EHsc"}); extend(ret, {"/EHsc"});
} }
extend(ret, {"/nologo", "/permissive-", "[flags]", "/c", "[in]", "/Fo[out]"}); extend(ret, {"/nologo", "/permissive-", "[flags]", "/c", "[in]", "/Fo[out]"});
} else if (is_gnu_like) { } else if (is_gnu_like) {
if (do_optimize.has_value() && *do_optimize) {
extend(ret, {"-O2"});
}
if (do_debug.has_value() && *do_debug) {
extend(ret, {"-g"});
}
extend(ret, {"-fPIC", "-pthread", "[flags]", "-c", "[in]", "-o[out]"}); extend(ret, {"-fPIC", "-pthread", "[flags]", "-c", "[in]", "-o[out]"});
} }
if (common_flags) { if (common_flags) {

+ 44
- 3
src/dds/toolchain/from_json.test.cpp View File

"ar rcs stuff.a foo.o bar.o", "ar rcs stuff.a foo.o bar.o",
"g++ -fPIC foo.o bar.a -pthread -omeow.exe -O2 -g"); "g++ -fPIC foo.o bar.a -pthread -omeow.exe -O2 -g");


check_tc_compile(
"{compiler_id: 'gnu', debug: 'split', optimize: true}",
"g++ -O2 -g -gsplit-dwarf -fPIC -pthread -MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o",
"g++ -O2 -g -gsplit-dwarf -fPIC -pthread -Wall -Wextra -Wpedantic -Wconversion -MD -MF "
"foo.o.d -MT foo.o -c foo.cpp -ofoo.o",
"ar rcs stuff.a foo.o bar.o",
"g++ -fPIC foo.o bar.a -pthread -omeow.exe -O2 -g -gsplit-dwarf");

check_tc_compile("{compiler_id: 'msvc'}", check_tc_compile("{compiler_id: 'msvc'}",
"cl.exe /MT /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o", "cl.exe /MT /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /MT /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o", "cl.exe /MT /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o",


check_tc_compile( check_tc_compile(
"{compiler_id: 'msvc', debug: true}", "{compiler_id: 'msvc', debug: true}",
"cl.exe /Z7 /DEBUG /MTd /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /Z7 /DEBUG /MTd /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /MTd /Z7 /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /MTd /Z7 /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o",
"lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MTd /Z7");

check_tc_compile(
"{compiler_id: 'msvc', debug: 'embedded'}",
"cl.exe /MTd /Z7 /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /MTd /Z7 /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o",
"lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MTd /Z7");

check_tc_compile(
"{compiler_id: 'msvc', debug: 'split'}",
"cl.exe /MTd /Zi /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /MTd /Zi /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o",
"lib /nologo /OUT:stuff.a foo.o bar.o", "lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /Z7 /DEBUG /MTd");
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MTd /Zi");


check_tc_compile( check_tc_compile(
"{compiler_id: 'msvc', flags: '-DFOO'}", "{compiler_id: 'msvc', flags: '-DFOO'}",
"cl.exe /MT /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o -DFOO", "cl.exe /MT /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o -DFOO",
"lib /nologo /OUT:stuff.a foo.o bar.o", "lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MT"); "cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MT");

check_tc_compile("{compiler_id: 'msvc', runtime: {static: false}}",
"cl.exe /MD /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /MD /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o",
"lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MD");

check_tc_compile(
"{compiler_id: 'msvc', runtime: {static: false}, debug: true}",
"cl.exe /MDd /Z7 /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /MDd /Z7 /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o",
"lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MDd /Z7");

check_tc_compile("{compiler_id: 'msvc', runtime: {static: false, debug: true}}",
"cl.exe /MDd /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /MDd /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o",
"lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MDd");
} }


TEST_CASE("Manipulate a toolchain and file compilation") { TEST_CASE("Manipulate a toolchain and file compilation") {

Loading…
Cancel
Save