#!/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")); }