From 55ea88f66f23f9a2b844ad6a9d2d41f98f299a04 Mon Sep 17 00:00:00 2001 From: Sebastian Wilzbach Date: Tue, 26 Dec 2017 00:50:32 +0100 Subject: [PATCH] Implement -probe for showing supported features --- src/dmd/globals.d | 1 + src/dmd/lexer.d | 59 ++++++++----- src/dmd/mars.d | 12 +++ src/dmd/probing.d | 161 ++++++++++++++++++++++++++++++++++ src/posix.mak | 5 +- src/win32.mak | 2 +- test/runnable/test_probing.sh | 12 +++ 7 files changed, 229 insertions(+), 23 deletions(-) create mode 100644 src/dmd/probing.d create mode 100755 test/runnable/test_probing.sh diff --git a/src/dmd/globals.d b/src/dmd/globals.d index 1e0136f9834d..1dc1e176dbbf 100644 --- a/src/dmd/globals.d +++ b/src/dmd/globals.d @@ -151,6 +151,7 @@ struct Param bool mcpuUsage; // print help on -mcpu switch bool transitionUsage; // print help on -transition switch bool logo; // print compiler logo + bool showProbingInfo; // print detailed information about the compiler CPU cpu = CPU.baseline; // CPU instruction set to target diff --git a/src/dmd/lexer.d b/src/dmd/lexer.d index 3862f06414a5..a514132965ff 100644 --- a/src/dmd/lexer.d +++ b/src/dmd/lexer.d @@ -194,6 +194,44 @@ unittest } } +long parseVersionXX(const(char)* _version) +{ + struct Version + { + uint major; + uint minor; + bool point; + } + Version rVersion; + + with(rVersion) + for (const(char)* p = _version + 1; 1; p++) + { + const c = *p; + if (isdigit(cast(char)c)) + minor = minor * 10 + c - '0'; + else if (c == '.') + { + if (point) + break; // ignore everything after second '.' + point = true; + major = minor; + minor = 0; + } + else + break; + } + return rVersion.major * 1000 + rVersion.minor; +} + +unittest +{ + assert(parseVersionXX("v2.078.0-265-g4a9eac019-dirty") == 2078); + assert(parseVersionXX("v2.078.0") == 2078); + assert(parseVersionXX("v2.078.1") == 2078); + assert(parseVersionXX("v2.070.2-rc.2") == 2070); +} + /*********************************************************** */ class Lexer @@ -516,27 +554,8 @@ class Lexer } else if (id == Id.VERSIONX) { - uint major = 0; - uint minor = 0; - bool point = false; - for (const(char)* p = global._version + 1; 1; p++) - { - const c = *p; - if (isdigit(cast(char)c)) - minor = minor * 10 + c - '0'; - else if (c == '.') - { - if (point) - break; // ignore everything after second '.' - point = true; - major = minor; - minor = 0; - } - else - break; - } t.value = TOKint64v; - t.unsvalue = major * 1000 + minor; + t.unsvalue = parseVersionXX(global._version); } else if (id == Id.EOFX) { diff --git a/src/dmd/mars.d b/src/dmd/mars.d index 6fefe342f00b..5609136c78da 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -472,6 +472,13 @@ private int tryMain(size_t argc, const(char)** argv) Objc._init(); builtin_init(); + if (global.params.showProbingInfo) + { + import dmd.probing : printProbingInfo; + printProbingInfo(); + return EXIT_SUCCESS; + } + if (global.params.verbose) { fprintf(global.stdmsg, "binary %s\n", global.params.argv0); @@ -2098,6 +2105,11 @@ private bool parseCommandLine(const ref Strings arguments, const size_t argc, re params.manual = true; return false; } + else if (strcmp(p + 1, "probe") == 0) // not documented for 2.079 + { + params.showProbingInfo = true; + return false; + } else if (arg == "-run") // https://dlang.org/dmd.html#switch-run { params.run = true; diff --git a/src/dmd/probing.d b/src/dmd/probing.d new file mode 100644 index 000000000000..96d6e6e56c89 --- /dev/null +++ b/src/dmd/probing.d @@ -0,0 +1,161 @@ +/** + * Compiler implementation of the + * $(LINK2 http://www.dlang.org, D programming language). + * + * This modules helps to create a list of supported features (aka probing output). + * The probing information is returned in JSON. + * + * Copyright: Copyright (c) 1999-2018 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/probing.d, _probing.d) + * Documentation: https://dlang.org/phobos/dmd_probing.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/probing.d + */ + +module dmd.probing; + +/** +Prints a list of supported features (aka probing output) to stdout. +The output is in JSON. +*/ +void printProbingInfo() +{ + import core.stdc.stdio : printf; + import dmd.globals : global; + + printf("{\n"); + bool needsComma; + void printKey(const(char*) key, void function() value) + { + if (needsComma) + printf(","); + printf("\n"); + needsComma = true; + printf(" \"%s\": ", key); + value(); + } + + printKey("compiler", (){ + printf(`"%s"`, determineCompiler()); + }); + printKey("frontendVersion", (){ + printf("%d", versionXX()); + }); + printKey("compilerFrontend", (){ + printf(`"%s"`, global._version); + }); + printKey("config", (){ + if (*global.inifilename != '\0') + printf(`"%s"`, global.inifilename); + else + printf("null"); + }); + printKey("binary", (){ + printf(`"%s"`, global.params.argv0); + }); + printKey("platform", (){ + printJSONArray(&determinePlatform); + }); + printKey("architecture", (){ + printJSONArray(&determineArchitecture); + }); + printKey("predefinedVersions", (){ + printJSONArray(&predefinedVersions); + }); + printf("\n}\n"); +} + +private long versionXX() +{ + import dmd.lexer : parseVersionXX; + import dmd.globals : global; + return global._version.parseVersionXX; +} + +private const(char*) determineCompiler() +{ + import core.stdc.string : strcmp; + import dmd.globals : global; + + if (strcmp(global.compiler.vendor, "Digital Mars D") == 0) + return "dmd"; + else if (strcmp(global.compiler.vendor, "LDC") == 0) + return "ldc"; + else if (strcmp(global.compiler.vendor, "GNU") == 0) + return "gdc"; + else if (strcmp(global.compiler.vendor, "SDC") == 0) + return "sdc"; + + return null; +}; + +private void printJSONArray(void function(void delegate(string)) fun) +{ + import core.stdc.stdio : printf; + static immutable const(char*) indent = " "; + + bool isFirst = true; + printf("[\n"); + void print(string s) + { + if (!isFirst) + printf(",\n"); + printf(`%s%s"%s"`, indent, indent, s.ptr); + isFirst = false; + } + fun(&print); + printf("\n%s]", indent); +} + +private void determinePlatform(void delegate(string) print) +{ + import dmd.globals : global; + + if (global.params.isWindows) + { + print("windows"); + } + else + { + print("posix"); + if (global.params.isLinux) + print("linux"); + if (global.params.isOSX) + print("osx"); + if (global.params.isFreeBSD) + { + print("freebsd"); + print("bsd"); + } + if (global.params.isOpenBSD) + { + print("openbsd"); + print("bsd"); + } + if (global.params.isSolaris) + { + print("solaris"); + print("bsd"); + } + } +} + +private void determineArchitecture(void delegate(string) print) +{ + import dmd.globals : global; + + if (global.params.is64bit) + print("x86_64"); + else + version(X86) print("x86"); +} + +private void predefinedVersions(void delegate(string) print) +{ + import dmd.globals : global; + foreach (const s; *global.versionids) + { + print(cast(string) s.toString); + } +} diff --git a/src/posix.mak b/src/posix.mak index 276ac94ac0de..e03fa7a438dd 100644 --- a/src/posix.mak +++ b/src/posix.mak @@ -296,7 +296,8 @@ FRONT_SRCS=$(addsuffix .d, $(addprefix $D/,access aggregate aliasthis apply argt dinifile dinterpret dmacro dmangle dmodule doc dscope dstruct dsymbol dsymbolsem \ dtemplate dversion escape expression expressionsem func \ hdrgen id impcnvtab imphint init initsem inline inlinecost intrange \ - json lib libelf libmach link mars mtype nogc nspace objc opover optimize parse permissivevisitor sapply templateparamsem \ + json lib libelf libmach link mars mtype nogc nspace objc opover optimize parse permissivevisitor \ + probing sapply templateparamsem \ sideeffect statement staticassert target typesem traits transitivevisitor parsetimevisitor visitor \ typinf utils scanelf scanmach statement_rewrite_walker statementsem staticcond safe blockexit printast \ semantic2 semantic3)) @@ -457,7 +458,7 @@ $G/dmd: $(DMD_SRCS) $(ROOT_SRCS) $G/newdelete.o $G/backend.a $G/lexer.a $(STRING CC="$(HOST_CXX)" $(HOST_DMD_RUN) -of$@ $(MODEL_FLAG) -vtls -J$G -J../res -L-lstdc++ $(DFLAGS) $(filter-out $(STRING_IMPORT_FILES) $(HOST_DMD_PATH) $(LEXER_ROOT) $G/dmd.conf,$^) endif -$G/dmd-unittest: $(DMD_SRCS) $(ROOT_SRCS) $G/newdelete.o $G/lexer.a $(G_GLUE_OBJS) $(G_OBJS) $(STRING_IMPORT_FILES) $(HOST_DMD_PATH) +$G/dmd-unittest: $(DMD_SRCS) $(ROOT_SRCS) $G/newdelete.o $G/lexer.a $(G_GLUE_OBJS) $(G_OBJS) $(STRING_IMPORT_FILES) $(HOST_DMD_PATH) $(LEXER_SRCS) CC=$(HOST_CXX) $(HOST_DMD_RUN) -of$@ $(MODEL_FLAG) -vtls -J$G -J../res -L-lstdc++ $(DFLAGS) -g -unittest -main -version=NoMain $(filter-out $(STRING_IMPORT_FILES) $(HOST_DMD_PATH),$^) unittest: $G/dmd-unittest diff --git a/src/win32.mak b/src/win32.mak index f1e98b8e3790..2669bc2cac56 100644 --- a/src/win32.mak +++ b/src/win32.mak @@ -157,7 +157,7 @@ FRONT_SRCS=$D/access.d $D/aggregate.d $D/aliasthis.d $D/apply.d $D/argtypes.d $D $D/expression.d $D/expressionsem.d $D/func.d $D/hdrgen.d $D/id.d $D/imphint.d \ $D/impcnvtab.d $D/init.d $D/initsem.d $D/inline.d $D/inlinecost.d $D/intrange.d $D/json.d $D/lib.d $D/link.d \ $D/mars.d $D/mtype.d $D/nogc.d $D/nspace.d $D/objc.d $D/opover.d $D/optimize.d $D/parse.d \ - $D/sapply.d $D/sideeffect.d $D/statement.d $D/staticassert.d $D/target.d \ + $D/probing.d $D/sapply.d $D/sideeffect.d $D/statement.d $D/staticassert.d $D/target.d \ $D/safe.d $D/blockexit.d $D/permissivevisitor.d $D/transitivevisitor.d $D/parsetimevisitor.d $D/printast.d $D/typesem.d \ $D/traits.d $D/utils.d $D/visitor.d $D/libomf.d $D/scanomf.d $D/templateparamsem.d $D/typinf.d \ $D/libmscoff.d $D/scanmscoff.d $D/statement_rewrite_walker.d $D/statementsem.d $D/staticcond.d \ diff --git a/test/runnable/test_probing.sh b/test/runnable/test_probing.sh new file mode 100755 index 000000000000..70426e79ac3c --- /dev/null +++ b/test/runnable/test_probing.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + + +if [ "${OS}" == "win32" -o "${OS}" == "win64" ]; then + expected="windows" +else + expected="posix" +fi + +"${DMD}" -probe | grep "${expected}"