diff --git a/appveyor.yml b/appveyor.yml index 7afd8bdd72..8ca2856b5d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -232,7 +232,7 @@ after_test: ren lib lib32 (cat etc\ldc2.conf).replace('%%ldcbinarypath%%/../lib', '%%ldcbinarypath%%/../lib64') | Set-Content etc\ldc2.conf $conf32 = cat ..\ldc2-x86\etc\ldc2.conf -Raw - $conf32 = "`r`ni686-pc-windows-msvc:" + $conf32.Substring($conf32.IndexOf("`r`ndefault:") + 10) + $conf32 = "`r`n""i[3-6]86-.*-windows-msvc"":" + $conf32.Substring($conf32.IndexOf("`r`ndefault:") + 10) $conf32 = $conf32.Replace('%%ldcbinarypath%%/../lib', '%%ldcbinarypath%%/../lib32') Add-Content etc\ldc2.conf $conf32 cd .. diff --git a/driver/config.d b/driver/config.d index ff5ce6cf13..65ab53e324 100644 --- a/driver/config.d +++ b/driver/config.d @@ -136,7 +136,7 @@ EBNF grammar. It is a subset of the libconfig grammar (http://www.hyperrealm.com/libconfig). config = { ows , setting } , ows ; -setting = name , (":" | "=") , value , [";" | ","] ; +setting = (name | string) , (":" | "=") , value , [";" | ","] ; name = alpha , { alpha | digit | "_" | "-" } ; value = string | array | group ; array = "[" , ows , @@ -445,14 +445,20 @@ struct Parser Setting parseSetting() { - immutable name = accept(Token.name); + string name; + auto t = getTok(name); + if (t != Token.name && t != Token.str) + { + unexpectedTokenError(t, Token.name, name); + assert(false); + } accept(Token.assign); Setting res = parseValue(name); string s; - immutable t = getTok(s); + t = getTok(s); if (t != Token.semicolon && t != Token.comma) { ungetTok(t, s); @@ -567,25 +573,25 @@ unittest `// comment // comment -group-1: {}; +group-1_2: {}; // comment -Group-2: +"86(_64)?-.*linux\\.?": { // comment scalar = "abc"; // comment - Array_1 = [ "a" ]; + Array_1-2 = [ "a" ]; }; `; auto settings = Parser(input).parseConfig(); assert(settings.length == 2); - assert(settings[0].name == "group-1"); + assert(settings[0].name == "group-1_2"); assert(settings[0].type == Setting.Type.group); assert((cast(GroupSetting) settings[0]).children == []); - assert(settings[1].name == "Group-2"); + assert(settings[1].name == "86(_64)?-.*linux\\.?"); assert(settings[1].type == Setting.Type.group); auto group2 = cast(GroupSetting) settings[1]; assert(group2.children.length == 2); @@ -594,7 +600,7 @@ Group-2: assert(group2.children[0].type == Setting.Type.scalar); assert((cast(ScalarSetting) group2.children[0]).val == "abc"); - assert(group2.children[1].name == "Array_1"); + assert(group2.children[1].name == "Array_1-2"); assert(group2.children[1].type == Setting.Type.array); assert((cast(ArraySetting) group2.children[1]).vals == [ "a" ]); } diff --git a/driver/configfile.cpp b/driver/configfile.cpp index 8b2ee77a0c..8e1d0a1bdb 100644 --- a/driver/configfile.cpp +++ b/driver/configfile.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" #include #include #include @@ -172,7 +173,7 @@ bool ConfigFile::locate(std::string &pathstr) { return false; } -bool ConfigFile::read(const char *explicitConfFile, const char *section) { +bool ConfigFile::read(const char *explicitConfFile, const char *triple) { std::string pathstr; // explicitly provided by user in command line? if (explicitConfFile) { @@ -201,7 +202,7 @@ bool ConfigFile::read(const char *explicitConfFile, const char *section) { pathcstr = strdup(pathstr.c_str()); auto binpath = exe_path::getBinDir(); - return readConfig(pathcstr, section, binpath.c_str()); + return readConfig(pathcstr, triple, binpath.c_str()); } void ConfigFile::extendCommandLine(llvm::SmallVectorImpl &args) { @@ -219,3 +220,7 @@ void ConfigFile::extendCommandLine(llvm::SmallVectorImpl &args) { args.insert(runIndex == 0 ? args.end() : args.begin() + runIndex, postSwitches.begin(), postSwitches.end()); } + +bool ConfigFile::sectionMatches(const char *section, const char *triple) { + return llvm::Regex(section).match(triple); +} diff --git a/driver/configfile.d b/driver/configfile.d index 3269ee3526..b4c237897c 100644 --- a/driver/configfile.d +++ b/driver/configfile.d @@ -29,27 +29,28 @@ string prepareBinDir(const(char)* binDir) return cast(string)res; // assumeUnique } - -ArraySetting findArraySetting(GroupSetting section, string name) +T findSetting(T)(GroupSetting[] sections, Setting.Type type, string name) { - if (!section) return null; - foreach (c; section.children) + // lexically later sections dominate earlier ones + foreach_reverse (section; sections) { - if (c.type == Setting.Type.array && c.name == name) - return cast(ArraySetting) c; + foreach (c; section.children) + { + if (c.type == type && c.name == name) + return cast(T) c; + } } return null; } -ScalarSetting findScalarSetting(GroupSetting section, string name) +ArraySetting findArraySetting(GroupSetting[] sections, string name) { - if (!section) return null; - foreach (c; section.children) - { - if (c.type == Setting.Type.scalar && c.name == name) - return cast(ScalarSetting) c; - } - return null; + return findSetting!ArraySetting(sections, Setting.Type.array, name); +} + +ScalarSetting findScalarSetting(GroupSetting[] sections, string name) +{ + return findSetting!ScalarSetting(sections, Setting.Type.scalar, name); } string replace(string str, string pattern, string replacement) @@ -107,47 +108,37 @@ private: Array!(const(char)*) postSwitches; const(char)* rpathcstr; - bool readConfig(const(char)* cfPath, const(char)* sectionName, const(char)* binDir) + static bool sectionMatches(const(char)* section, const(char)* triple); + + bool readConfig(const(char)* cfPath, const(char)* triple, const(char)* binDir) { switches.setDim(0); postSwitches.setDim(0); immutable dBinDir = prepareBinDir(binDir); - const dSec = sectionName[0 .. strlen(sectionName)]; try { - GroupSetting section, defaultSection; + GroupSetting[] sections; // in lexical order foreach (s; parseConfigFile(cfPath)) { - if (s.type != Setting.Type.group) - continue; - if (s.name == dSec) - section = cast(GroupSetting) s; - else if (s.name == "default") - defaultSection = cast(GroupSetting) s; + if (s.type == Setting.Type.group && + (s.name == "default" || sectionMatches((s.name ~ '\0').ptr, triple))) + { + sections ~= cast(GroupSetting) s; + } } - if (!section && !defaultSection) + if (sections.length == 0) { + const dTriple = triple[0 .. strlen(triple)]; const dCfPath = cfPath[0 .. strlen(cfPath)]; - if (sectionName) - throw new Exception("Could not look up section '" ~ cast(string) dSec - ~ "' nor the 'default' section in " ~ cast(string) dCfPath); - else - throw new Exception("Could not look up 'default' section in " ~ cast(string) dCfPath); + throw new Exception("No matching section for triple '" ~ cast(string) dTriple + ~ "' in " ~ cast(string) dCfPath); } - ArraySetting findArray(string name) - { - auto r = findArraySetting(section, name); - if (!r) - r = findArraySetting(defaultSection, name); - return r; - } - - auto switches = findArray("switches"); - auto postSwitches = findArray("post-switches"); + auto switches = findArraySetting(sections, "switches"); + auto postSwitches = findArraySetting(sections, "post-switches"); if (!switches && !postSwitches) { const dCfPath = cfPath[0 .. strlen(cfPath)]; @@ -170,16 +161,7 @@ private: applyArray(this.switches, switches); applyArray(this.postSwitches, postSwitches); - ScalarSetting findScalar(string name) - { - auto r = findScalarSetting(section, name); - if (!r) - r = findScalarSetting(defaultSection, name); - return r; - } - - auto rpath = findScalar("rpath"); - if (rpath) + if (auto rpath = findScalarSetting(sections, "rpath")) this.rpathcstr = (rpath.val.replace("%%ldcbinarypath%%", dBinDir) ~ '\0').ptr; return true; @@ -191,3 +173,10 @@ private: } } } + +unittest +{ + assert(ConfigFile.sectionMatches("i[3-6]86-.*-windows-msvc", "i686-pc-windows-msvc")); + assert(ConfigFile.sectionMatches("86(_64)?-.*-linux", "x86_64--linux-gnu")); + assert(!ConfigFile.sectionMatches("^linux", "x86_64--linux-gnu")); +} diff --git a/driver/configfile.h b/driver/configfile.h index 11381d22be..87584ac72a 100644 --- a/driver/configfile.h +++ b/driver/configfile.h @@ -24,7 +24,7 @@ class ConfigFile { public: static ConfigFile instance; - bool read(const char *explicitConfFile, const char *section); + bool read(const char *explicitConfFile, const char *triple); llvm::StringRef path() { return pathcstr ? llvm::StringRef(pathcstr) : llvm::StringRef(); @@ -38,9 +38,10 @@ public: private: bool locate(std::string &pathstr); + static bool sectionMatches(const char *section, const char *triple); // implemented in D - bool readConfig(const char *cfPath, const char *section, const char *binDir); + bool readConfig(const char *cfPath, const char *triple, const char *binDir); const char *pathcstr = nullptr; Array switches; diff --git a/ldc2.conf.in b/ldc2.conf.in index 0ecaaff428..db4572ae78 100644 --- a/ldc2.conf.in +++ b/ldc2.conf.in @@ -1,7 +1,19 @@ // See comments in driver/config.d in ldc source tree for grammar description of // this config file. -// The default group is required +// For cross-compilation, you can add sections for specific target triples by +// naming the sections as (quoted) regex patterns. See LDC's `-v` output +// (`config` line) to figure out your normalized triple, depending on the used +// `-mtriple`, `-m32` etc. E.g.: +// +// "^arm.*-linux-gnueabihf$": { … }; +// "86(_64)?-.*-linux": { … }; +// "i[3-6]86-.*-windows-msvc": { … }; +// +// Later sections take precedence and override settings from previous matching +// sections while inheriting unspecified settings from previous sections. +// A `default` section always matches (treated as ".*") and is therefore usually +// the first section. default: { // default switches injected before all explicit command-line switches diff --git a/ldc2_install.conf.in b/ldc2_install.conf.in index 27733e8432..34142b8eb6 100644 --- a/ldc2_install.conf.in +++ b/ldc2_install.conf.in @@ -1,7 +1,19 @@ // See comments in driver/config.d in ldc source tree for grammar description of // this config file. -// The default group is required +// For cross-compilation, you can add sections for specific target triples by +// naming the sections as (quoted) regex patterns. See LDC's `-v` output +// (`config` line) to figure out your normalized triple, depending on the used +// `-mtriple`, `-m32` etc. E.g.: +// +// "^arm.*-linux-gnueabihf$": { … }; +// "86(_64)?-.*-linux": { … }; +// "i[3-6]86-.*-windows-msvc": { … }; +// +// Later sections take precedence and override settings from previous matching +// sections while inheriting unspecified settings from previous sections. +// A `default` section always matches (treated as ".*") and is therefore usually +// the first section. default: { // default switches injected before all explicit command-line switches diff --git a/ldc2_phobos.conf.in b/ldc2_phobos.conf.in index 6e22fd14c3..c281bfa64b 100644 --- a/ldc2_phobos.conf.in +++ b/ldc2_phobos.conf.in @@ -1,7 +1,19 @@ // See comments in driver/config.d in ldc source tree for grammar description of // this config file. -// The default group is required +// For cross-compilation, you can add sections for specific target triples by +// naming the sections as (quoted) regex patterns. See LDC's `-v` output +// (`config` line) to figure out your normalized triple, depending on the used +// `-mtriple`, `-m32` etc. E.g.: +// +// "^arm.*-linux-gnueabihf$": { … }; +// "86(_64)?-.*-linux": { … }; +// "i[3-6]86-.*-windows-msvc": { … }; +// +// Later sections take precedence and override settings from previous matching +// sections while inheriting unspecified settings from previous sections. +// A `default` section always matches (treated as ".*") and is therefore usually +// the first section. default: { // default switches injected before all explicit command-line switches diff --git a/tests/driver/config_diag.d b/tests/driver/config_diag.d index 281ead8cd4..31cebd3cd7 100644 --- a/tests/driver/config_diag.d +++ b/tests/driver/config_diag.d @@ -2,7 +2,7 @@ // NOSWITCHES: Could not look up switches in {{.*}}noswitches.conf // RUN: not %ldc -conf=%S/inputs/section_aaa.conf %s 2>&1 | FileCheck %s --check-prefix=NO_SEC -// NO_SEC: Could not look up section '{{.*}}' nor the 'default' section in {{.*}}section_aaa.conf +// NO_SEC: No matching section for triple '{{.*}}' in {{.*}}section_aaa.conf void foo() diff --git a/tests/driver/inputs/override_default.conf b/tests/driver/inputs/override_default.conf index b21a736dcf..e0a66a8ce6 100644 --- a/tests/driver/inputs/override_default.conf +++ b/tests/driver/inputs/override_default.conf @@ -1,9 +1,9 @@ -x86-apple-windows-msvc: -{ - switches = [ "-version" ]; -}; - default: { switches = [ "" ]; }; + +x86-apple-windows-msvc: +{ + switches = [ "-version" ]; +};