mirror of
https://github.com/dlang/tools.git
synced 2025-04-25 12:40:21 +03:00
262 lines
7 KiB
D
Executable file
262 lines
7 KiB
D
Executable file
#!/usr/bin/env rdmd
|
|
/++
|
|
This Windows-only tool automatically downloads Win32 libcurl binaries and
|
|
generates a libcurl.lib compatible with Win32 DMD (which is needed by
|
|
std.net.curl and certain official DMD tools).
|
|
|
|
There are no prerequisites other than an active internet connection and a
|
|
working D compiler to compile this tool.
|
|
|
|
This tool is provided because, unlike Posix and Win64, the standard libcurl
|
|
binaries aren't compatible with the DMD linker used on Win32. Instead, "implib"
|
|
needs to be used to generate a compatible import library from libcurl.dll,
|
|
which this tool handles automatically.
|
|
+/
|
|
|
|
import std.algorithm;
|
|
import std.array;
|
|
import std.file;
|
|
import std.path;
|
|
import std.process;
|
|
import std.stdio;
|
|
import std.string;
|
|
|
|
version(Windows) {} else
|
|
{
|
|
static assert(false,
|
|
"This tool is only for Windows. On other systems, simply install "~
|
|
"libcurl through your OS's usual package manager.");
|
|
}
|
|
|
|
auto outputDir = "dlibcurl32";
|
|
|
|
immutable unzipUrl = "http://semitwist.com/download/app/unz600xn.exe";
|
|
immutable basicUtilsUrl = "http://ftp.digitalmars.com/bup.zip";
|
|
auto curlUrl = "http://curl.haxx.se/gknw.net/$(CURL_VERSION)/dist-w32/curl-$(CURL_VERSION)-rtmp-ssh2-ssl-sspi-zlib-idn-static-bin-w32.zip";
|
|
auto curlZipBase = "curl-$(CURL_VERSION)-rtmp-ssh2-ssl-sspi-zlib-idn-static-bin-w32";
|
|
|
|
immutable unzipArchiveName = "unzip-sfx.exe";
|
|
immutable basicUtilsArchiveName = "bup.zip";
|
|
immutable curlArchiveName = "curl.zip";
|
|
|
|
immutable workDirName = "get_dlibcurl32";
|
|
immutable dloadToolFilename = "download.vbs";
|
|
|
|
immutable dloadToolContent =
|
|
`Option Explicit
|
|
Dim args, http, fileSystem, adoStream, url, target, status
|
|
|
|
Set args = Wscript.Arguments
|
|
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
|
|
url = args(0)
|
|
target = args(1)
|
|
|
|
http.Open "GET", url, False
|
|
http.Send
|
|
status = http.Status
|
|
|
|
If status <> 200 Then
|
|
WScript.Echo "FAILED to download: HTTP Status " & status
|
|
WScript.Quit 1
|
|
End If
|
|
|
|
Set adoStream = CreateObject("ADODB.Stream")
|
|
adoStream.Open
|
|
adoStream.Type = 1
|
|
adoStream.Write http.ResponseBody
|
|
adoStream.Position = 0
|
|
|
|
Set fileSystem = CreateObject("Scripting.FileSystemObject")
|
|
If fileSystem.FileExists(target) Then fileSystem.DeleteFile target
|
|
adoStream.SaveToFile target
|
|
adoStream.Close
|
|
`;
|
|
|
|
string workDir;
|
|
string dloadToolPath;
|
|
bool hasImplib;
|
|
|
|
void showHelp()
|
|
{
|
|
stderr.writeln("Usage: get_dlibcurl32 LIBCURL_VERSION");
|
|
stderr.writeln("Ex: get_dlibcurl32 7.32.0");
|
|
}
|
|
|
|
int main(string[] args)
|
|
{
|
|
if(args.length != 2)
|
|
{
|
|
showHelp();
|
|
return 1;
|
|
}
|
|
|
|
if(args[1] == "--help")
|
|
{
|
|
showHelp();
|
|
return 0;
|
|
}
|
|
|
|
// Setup paths
|
|
auto curlVersion = args[1];
|
|
curlUrl = curlUrl .replace("$(CURL_VERSION)", curlVersion);
|
|
curlZipBase = curlZipBase.replace("$(CURL_VERSION)", curlVersion);
|
|
outputDir ~= "-" ~ curlVersion;
|
|
workDir = buildPath(tempDir(), workDirName);
|
|
|
|
checkImplib();
|
|
|
|
// Clear temporary work dir
|
|
writeln("Clearing temporary work dir: ", workDir);
|
|
removeDir(workDir);
|
|
makeDir(workDir);
|
|
|
|
// Archive paths
|
|
auto unzipArchivePath = buildPath(workDir, "unzip", unzipArchiveName);
|
|
auto basicUtilsArchivePath = buildPath(workDir, "bup", basicUtilsArchiveName);
|
|
auto curlArchivePath = buildPath(workDir, curlArchiveName);
|
|
makeDir(dirName(unzipArchivePath));
|
|
makeDir(dirName(basicUtilsArchivePath));
|
|
|
|
// Download
|
|
initDownloader();
|
|
download(unzipUrl, unzipArchivePath);
|
|
if(!hasImplib)
|
|
download(basicUtilsUrl, basicUtilsArchivePath);
|
|
download(curlUrl, curlArchivePath);
|
|
|
|
// Extract
|
|
{
|
|
auto saveDir = getcwd();
|
|
scope(exit) chdir(saveDir);
|
|
|
|
chdir(dirName(unzipArchivePath));
|
|
run(unzipArchiveName); // Self-extracting archive
|
|
|
|
if(!hasImplib)
|
|
{
|
|
chdir(dirName(basicUtilsArchivePath));
|
|
unzip(basicUtilsArchiveName);
|
|
}
|
|
|
|
chdir(workDir);
|
|
unzip(curlArchivePath);
|
|
}
|
|
|
|
// Generate import lib
|
|
auto curlDir = buildPath(workDir, curlZipBase);
|
|
implib(buildPath(curlDir, "libcurl"));
|
|
|
|
// Copy results out of temp dir
|
|
writeln("Copying results to '", outputDir, "'");
|
|
removeDir(outputDir);
|
|
copyDir(curlDir, outputDir);
|
|
|
|
writeln("Done.");
|
|
writeln("Your OPTLINK-compatable libcurl.lib, along with the rest of libcurl,");
|
|
writeln("is in the directory: ", outputDir);
|
|
|
|
return 0;
|
|
}
|
|
|
|
string quote(string str)
|
|
{
|
|
return `"` ~ str ~ `"`;
|
|
}
|
|
|
|
/// Recursively copy contents of 'src' directory into 'dest' directory.
|
|
/// Directory 'dest' will be created if it doesn't exist.
|
|
void copyDir(string src, string dest)
|
|
{
|
|
// Needed to generate 'relativePath' correctly.
|
|
if(!src.endsWith(dirSeparator))
|
|
src ~= dirSeparator;
|
|
|
|
makeDir(dest);
|
|
foreach(DirEntry entry; dirEntries(src, SpanMode.breadth))
|
|
{
|
|
auto relativePath = entry.name.chompPrefix(src);
|
|
|
|
auto destPath = buildPath(dest, relativePath);
|
|
if(entry.isDir)
|
|
makeDir(destPath);
|
|
else
|
|
{
|
|
makeDir(dirName(destPath));
|
|
copy(buildPath(src, relativePath), destPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Remove entire directory tree. If it doesn't exist, do nothing.
|
|
void removeDir(string path)
|
|
{
|
|
if(exists(path))
|
|
{
|
|
auto failMsg =
|
|
"Failed to remove directory: "~path~"\n"~
|
|
" A process may still holding an open handle within the directory.\n"~
|
|
" Either delete the directory manually or try again later.";
|
|
|
|
try
|
|
system("rmdir /S /Q "~quote(path));
|
|
catch(Exception e)
|
|
throw new Exception(failMsg);
|
|
|
|
if(exists(path))
|
|
throw new Exception(failMsg);
|
|
}
|
|
}
|
|
|
|
/// Like mkdirRecurse, but no error if directory already exists.
|
|
void makeDir(string path)
|
|
{
|
|
if(!exists(path))
|
|
mkdirRecurse(path);
|
|
}
|
|
|
|
void initDownloader()
|
|
{
|
|
dloadToolPath = buildPath(workDir, dloadToolFilename);
|
|
std.file.write(dloadToolPath, dloadToolContent);
|
|
}
|
|
|
|
void checkImplib()
|
|
{
|
|
try
|
|
hasImplib = executeShell("implib /h").output.startsWith("Digital Mars Import Library Manager");
|
|
catch(Exception e)
|
|
hasImplib = false;
|
|
}
|
|
|
|
void run(string cmd)
|
|
{
|
|
auto errlevel = system(cmd);
|
|
if(errlevel != 0)
|
|
throw new Exception("Command failed: "~cmd~"\n Ran from dir: "~getcwd());
|
|
}
|
|
|
|
void download(string url, string target)
|
|
{
|
|
writeln("Downloading: ", url);
|
|
run("cscript //Nologo "~quote(dloadToolPath)~" "~quote(url)~" "~quote(target));
|
|
}
|
|
|
|
void unzip(string path)
|
|
{
|
|
writeln("Unzipping: ", path);
|
|
auto unzipTool = buildPath(workDir, `unzip\unzip.exe`);
|
|
run(unzipTool~" -q "~quote(path));
|
|
}
|
|
|
|
/// 'libName' includes path, but NOT extension
|
|
void implib(string libName)
|
|
{
|
|
writeln("Generating Import Lib: ", libName);
|
|
auto saveDir = getcwd();
|
|
scope(exit) chdir(saveDir);
|
|
|
|
chdir(dirName(libName));
|
|
auto implibTool = hasImplib? "implib" : buildPath(workDir, `bup\dm\bin\implib.exe`);
|
|
auto libBaseName = baseName(libName);
|
|
run(implibTool~" /s "~quote(libBaseName~".lib")~" "~quote(libBaseName~".dll"));
|
|
}
|