1 /+ dub.sdl:
2  name "script"
3  +/
4 
5 /**
6  * This program will attempt to detect which version of openssl is installed
7  *
8  * End-users might have different versions of OpenSSL installed.
9  * The version might ever differ among members of a development team.
10  *
11  * This script attempts to first calls `pkg-config` to find out the version,
12  * then reverts to calling the `openssl` binary if `pkg-config` didn't work.
13  *
14  * It is called directly as a `preGenerateCommand` (see dub.sdl).
15  * To use it with another build system, pass the directory in which to write
16  * the `version_.di` file as first and only argument. The directory
17  * must exist, this script will not create it.
18  */
19 module generate_version;
20 
21 import std.algorithm;
22 import std.conv;
23 import std.file;
24 import std.functional;
25 import std.path;
26 import std.process;
27 import std.range;
28 import std.stdio;
29 import std.string;
30 import std.uni;
31 
32 // file full path is: $SOME_PATH/openssl/scripts/generate_version.d
33 // We want: $SOME_PATH/openssl/source/deimos/openssl/
34 immutable TARGET_DIR_PATH = __FILE_FULL_PATH__
35     .dirName.dirName.buildPath("source", "deimos", "openssl");
36 
37 void main(string[] args)
38 {
39     string target;
40 
41     if (args.length == 2)
42     {
43         assert(args[1].isDir(),
44                "OpenSSL version detection: Argument '" ~ args[1] ~ "' is not a directory");
45         target = args[1].buildPath("version_.di");
46     }
47     else
48     {
49         assert(args.length == 1,
50                "OpenSSL version detection expects only one argument, " ~
51                "a directory path where to write `version_.di`");
52         target = TARGET_DIR_PATH.buildPath("version_.di");
53     }
54 
55     string opensslVersion;
56     try
57     {
58         const res = execute(["pkg-config", "openssl", "--modversion"]);
59         if (res.status == 0)
60             opensslVersion = res.output.strip();
61     }
62     catch (Exception e) {}
63 
64     if (!opensslVersion.length) try
65     {
66         const res = execute(["openssl", "version"]).output;
67         if (res.canFind("OpenSSL "))
68         {
69             opensslVersion = res.splitter(" ").dropOne.front.filter!(not!(std.uni.isAlpha)).text;
70         }
71         else if (res.canFind("LibreSSL "))
72         {
73             writeln("\tWarning: Your default openssl binary points to LibreSSL, which is not supported.");
74             version (OSX)
75             {
76                 writeln("\tOn Mac OSX, this is the default behavior.");
77                 writeln("\tIf you installed openssl via a package manager, you need to tell DUB how to find it.");
78                 writeln("\tAssuming brew, run [brew link openssl] and follow the instructions for pkg-config.\n");
79             }
80         }
81     }
82     catch (Exception e) {}
83 
84     if (!opensslVersion.length)
85     {
86          writeln("\tWarning: Could not find OpenSSL version via pkg-config nor by calling the openssl binary.");
87          writeln("\tAssuming version 1.1.0.");
88          writeln("\tYou might need to export PKG_CONFIG_PATH or install the openssl package if you have a library-only package.");
89          opensslVersion = "1.1.0h";
90     }
91     auto data = format(q{/**
92  * Provide the version of the libssl being linked to at compile time
93  *
94  * This module was auto-generated by deimos/openssl's script/generate_version.d
95  * Manual edit might get overwritten by later build.
96  *
97  * This module should not be directly dependend upon.
98  * Instead, use `deimos.openssl.opensslv`, which handles explicit overrides
99  * provides a uniform interface, and a few utilities.
100  */
101 module deimos.openssl.version_;
102 
103 /// Ditto
104 package enum OpenSSLTextVersion = "%s";
105 }, opensslVersion);
106 
107     // Only write the file iff it has changed or didn't exist before.
108     // This way timestamp-based build system will not rebuild,
109     // and changes on the installed OpenSSL will be correctly detected.
110     if (!target.exists || target.readText.strip != data.strip)
111         data.toFile(target);
112 }