diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d index bb34cde..d6df1bd 100644 --- a/source/dub/compilers/compiler.d +++ b/source/dub/compilers/compiler.d @@ -8,6 +8,7 @@ module dub.compilers.compiler; public import dub.compilers.buildsettings; +public import dub.platform : BuildPlatform, matchesSpecification; import dub.compilers.dmd; import dub.compilers.gdc; @@ -280,82 +281,6 @@ } -/// Represents a platform a package can be build upon. -struct BuildPlatform { - /// e.g. ["posix", "windows"] - string[] platform; - /// e.g. ["x86", "x86_64"] - string[] architecture; - /// Canonical compiler name e.g. "dmd" - string compiler; - /// Compiler binary name e.g. "ldmd2" - string compilerBinary; - /// Compiled frontend version (e.g. 2065) - int frontendVersion; - - enum any = BuildPlatform(null, null, null, null, -1); - - /// Build platforms can be specified via a string specification. - /// - /// Specifications are build upon the following scheme, where each component - /// is optional (indicated by []), but the order is obligatory. - /// "[-platform][-architecture][-compiler]" - /// - /// So the following strings are valid specifications: - /// "-windows-x86-dmd" - /// "-dmd" - /// "-arm" - /// "-arm-dmd" - /// "-windows-dmd" - /// - /// Params: - /// specification = The specification being matched. It must be the empty string or start with a dash. - /// - /// Returns: - /// true if the given specification matches this BuildPlatform, false otherwise. (The empty string matches) - /// - bool matchesSpecification(const(char)[] specification) - const { - import std.string : format; - - if (specification.empty) return true; - if (this == any) return true; - - auto splitted=specification.splitter('-'); - assert(!splitted.empty, "No valid platform specification! The leading hyphen is required!"); - splitted.popFront(); // Drop leading empty match. - enforce(!splitted.empty, format("Platform specification, if present, must not be empty: \"%s\"", specification)); - if (platform.canFind(splitted.front)) { - splitted.popFront(); - if(splitted.empty) - return true; - } - if (architecture.canFind(splitted.front)) { - splitted.popFront(); - if(splitted.empty) - return true; - } - if (compiler == splitted.front) { - splitted.popFront(); - enforce(splitted.empty, "No valid specification! The compiler has to be the last element!"); - return true; - } - return false; - } - unittest { - auto platform=BuildPlatform(["posix", "linux"], ["x86_64"], "dmd"); - assert(platform.matchesSpecification("-posix")); - assert(platform.matchesSpecification("-linux")); - assert(platform.matchesSpecification("-linux-dmd")); - assert(platform.matchesSpecification("-linux-x86_64-dmd")); - assert(platform.matchesSpecification("-x86_64")); - assert(!platform.matchesSpecification("-windows")); - assert(!platform.matchesSpecification("-ldc")); - assert(!platform.matchesSpecification("-windows-dmd")); - } -} - - string getTargetFileName(in BuildSettings settings, in BuildPlatform platform) { assert(settings.targetName.length > 0, "No target name set."); @@ -414,6 +339,7 @@ fil.close(); } + // NOTE: This must be kept in sync with the dub.platform module fil.write(q{ module dub_platform_probe; diff --git a/source/dub/platform.d b/source/dub/platform.d index acc9baf..8350a21 100644 --- a/source/dub/platform.d +++ b/source/dub/platform.d @@ -1,7 +1,14 @@ /** - Determines the strings to identify the current build platform. + Build platform identification and speficiation matching. - Copyright: © 2012 rejectedsoftware e.K. + This module is useful for determining the build platform for a certain + machine and compiler invocation. Example applications include classifying + CI slave machines. + + It also contains means to match build platforms against a platform + specification string as used in package reciptes. + + Copyright: © 2012-2016 rejectedsoftware e.K. License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. Authors: Sönke Ludwig */ @@ -9,6 +16,33 @@ import std.array; + +/** Determines the full build platform used for the current build. + + Note that the `BuildPlatform.compilerBinary` field will be left empty. + + See_Also: `determinePlatform`, `determineArchitecture`, `determineCompiler` +*/ +BuildPlatform determineBuildPlatform() +{ + BuildPlatform ret; + ret.platform = determinePlatform(); + ret.architecture = determineArchitecture(); + ret.compiler = determineCompiler(); + ret.frontendVersion = __VERSION__; + return ret; +} + + +/** Returns a list of platform identifiers that apply to the current + build. + + Example results are `["windows"]` or `["posix", "osx"]`. The identifiers + correspond to the compiler defined version constants built into the + language, except that they are converted to lower case. + + See_Also: `determineBuildPlatform` +*/ string[] determinePlatform() { auto ret = appender!(string[])(); @@ -34,6 +68,15 @@ return ret.data; } +/** Returns a list of architecture identifiers that apply to the current + build. + + Example results are `["x86_64"]` or `["arm", "arm_softfloat"]`. The + identifiers correspond to the compiler defined version constants built into + the language, except that they are converted to lower case. + + See_Also: `determineBuildPlatform` +*/ string[] determineArchitecture() { auto ret = appender!(string[])(); @@ -77,6 +120,13 @@ return ret.data; } +/** Determines the canonical compiler name used for the current build. + + The possible values currently are "dmd", "gdc", "ldc2" or "sdc". If an + unknown compiler is used, this function will return an empty string. + + See_Also: `determineBuildPlatform` +*/ string determineCompiler() { version(DigitalMars) return "dmd"; @@ -85,3 +135,85 @@ else version(SDC) return "sdc"; else return null; } + +/** Matches a platform specification string against a build platform. + + Specifications are build upon the following scheme, where each component + is optional (indicated by []), but the order is obligatory: + "[-platform][-architecture][-compiler]" + + So the following strings are valid specifications: `"-windows-x86-dmd"`, + `"-dmd"`, `"-arm"`, `"-arm-dmd"`, `"-windows-dmd"` + + Params: + platform = The build platform to match agains the platform specification + specification = The specification being matched. It must either be an + empty string or start with a dash. + + Returns: + `true` if the given specification matches the build platform, `false` + otherwise. Using an empty string as the platform specification will + always result in a match. +*/ +bool matchesSpecification(in BuildPlatform platform, const(char)[] specification) +{ + import std.string : format; + import std.algorithm : canFind, splitter; + import std.exception : enforce; + + if (specification.empty) return true; + if (platform == BuildPlatform.any) return true; + + auto splitted = specification.splitter('-'); + assert(!splitted.empty, "No valid platform specification! The leading hyphen is required!"); + splitted.popFront(); // Drop leading empty match. + enforce(!splitted.empty, format("Platform specification, if present, must not be empty: \"%s\"", specification)); + + if (platform.platform.canFind(splitted.front)) { + splitted.popFront(); + if (splitted.empty) + return true; + } + if (platform.architecture.canFind(splitted.front)) { + splitted.popFront(); + if (splitted.empty) + return true; + } + if (platform.compiler == splitted.front) { + splitted.popFront(); + enforce(splitted.empty, "No valid specification! The compiler has to be the last element!"); + return true; + } + return false; +} + +/// +unittest { + auto platform=BuildPlatform(["posix", "linux"], ["x86_64"], "dmd"); + assert(platform.matchesSpecification("")); + assert(platform.matchesSpecification("-posix")); + assert(platform.matchesSpecification("-linux")); + assert(platform.matchesSpecification("-linux-dmd")); + assert(platform.matchesSpecification("-linux-x86_64-dmd")); + assert(platform.matchesSpecification("-x86_64")); + assert(!platform.matchesSpecification("-windows")); + assert(!platform.matchesSpecification("-ldc")); + assert(!platform.matchesSpecification("-windows-dmd")); +} + +/// Represents a platform a package can be build upon. +struct BuildPlatform { + /// Special constant used to denote matching any build platform. + enum any = BuildPlatform(null, null, null, null, -1); + + /// Platform identifiers, e.g. ["posix", "windows"] + string[] platform; + /// CPU architecture identifiers, e.g. ["x86", "x86_64"] + string[] architecture; + /// Canonical compiler name e.g. "dmd" + string compiler; + /// Compiler binary name e.g. "ldmd2" + string compilerBinary; + /// Compiled frontend version (e.g. `2067` for frontend versions 2.067.x) + int frontendVersion; +}