Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build mingw COFF libraries #289

Merged
merged 5 commits into from
Feb 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 3 additions & 21 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
language: c

addons:
apt:
# https://github.com/SimonKagstrom/kcov/blob/master/INSTALL.md#user-content-ubuntu
packages: [shellcheck, binutils-dev, libcurl4-openssl-dev, zlib1g-dev, libdw-dev, libiberty-dev]

matrix:
include:
- os: linux
install:
- KCOV_VERSION=34
- curl -fsSL https://github.com/SimonKagstrom/kcov/archive/v"$KCOV_VERSION".tar.gz | tar -C "$HOME" -zxf -
- pushd "$HOME/kcov-$KCOV_VERSION"
- cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local .
- make install -j$(nproc)
- popd
script: kcov --exclude-pattern=travis.sh $PWD/coverage ./travis.sh
after_success: bash <(curl -s https://codecov.io/bash) -s $PWD/coverage
- os: osx
script: ./travis.sh
branches:
except:
- /^build-/
16 changes: 16 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
os: Visual Studio 2017

environment:
matrix:
- ARCH: x86
MINGW_VER: 5.0.2
D_VERSION: 2.077.1

artifacts:
- path: mingw-libs-$(MINGW_VER).zip
name: mingwlibs

build_script:
- call windows\build_mingw.bat

test_script: true
46 changes: 46 additions & 0 deletions windows/build_mingw.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
@setlocal

set ROOT=%CD%

set DMD_URL=http://downloads.dlang.org/releases/2.x/%D_VERSION%/dmd.%D_VERSION%.windows.7z
echo DMD_URL=%DMD_URL%
appveyor DownloadFile %DMD_URL% -FileName dmd2.7z || exit /B 1
7z x dmd2.7z || exit /B 1
set PATH=%ROOT%\dmd2\windows\bin;%PATH%

echo b80b0c9d0158f9125e482b50fe00b70dde11d7a015ee687ca455fe2ea2ec8733 *w32api.src.tar.xz> sha256sums
echo 77233333f5440287840d134804bcecf3144ec3efc7fd7f7c6dce318e4e7146ee *mingwrt.src.tar.xz>> sha256sums

set MINGW_BASEURL=https://sourceforge.net/projects/mingw/files/MinGW/Base/
set W32API_URL=%MINGW_BASEURL%/w32api/w32api-%MINGW_VER%/w32api-%MINGW_VER%-mingw32-src.tar.xz
set MINGWRT_URL=%MINGW_BASEURL%/mingwrt/mingwrt-%MINGW_VER%/mingwrt-%MINGW_VER%-mingw32-src.tar.xz

appveyor DownloadFile %W32API_URL% -FileName w32api.src.tar.xz || exit /B 1
appveyor DownloadFile %MINGWRT_URL% -FileName mingwrt.src.tar.xz || exit /B 1

:: e.g. from git installation
sha256sum -c sha256sums || exit /B 1

7z x w32api.src.tar.xz || exit /B 1
7z x w32api.src.tar || exit /B 1

7z x mingwrt.src.tar.xz || exit /B 1
7z x mingwrt.src.tar || exit /B 1

move w32api-%MINGW_VER% w32api
move mingwrt-%MINGW_VER% mingwrt

cd windows\mingw
set w32api_lib=../../w32api/lib
set msvcrt_def_in=../../mingwrt/msvcrt-xref/msvcrt.def.in

call "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
rem CWD might be changed by vcvars64.bat
cd %ROOT%\windows\mingw
dmd -run buildsdk.d x64 %w32api_lib% dmd2\windows\lib64 %msvcrt_def_in% || exit /B 1

call "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat"
cd %ROOT%\windows\mingw
dmd -run buildsdk.d x86 %w32api_lib% dmd2\windows\lib32mscoff %msvcrt_def_in% || exit /B 1

7z a %ROOT%\mingw-libs-%MINGW_VER%.zip dmd2\windows
192 changes: 192 additions & 0 deletions windows/mingw/buildsdk.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
//
// Convert MingGW definition files to COFF import librries
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// usage: buildsdk [x86|x64] [def-folder] [output-folder] [msvcrt.def.in]
//
// Source files extracted from the MinGW reositories
//
// def-folder: https://sourceforge.net/p/mingw/mingw-org-wsl/ci/5.0-active/tree/w32api/lib/
// msvcrt.def.in: https://sourceforge.net/p/mingw/mingw-org-wsl/ci/5.0-active/tree/mingwrt/msvcrt-xref/msvcrt.def.in
//
// assumes VC tools cl,link,lib and ml installed and found through path
// and configured to the appropriate architecture
//

import std.file;
import std.regex;
import std.string;
import std.stdio;
import std.path;
import std.process;
import std.algorithm;

version = verbose;

void runShell(string cmd)
{
version(verbose)
writeln(cmd);
auto rc = executeShell(cmd);
if (rc.status)
{
writeln("'", cmd, "' failed with status ", rc.status);
writeln(rc.output);
throw new Exception("'" ~ cmd ~ "' failed");
}
}

// x86: the exported symbols have stdcall mangling (including trailing @n)
// but the internal names of the platform DLLs have names with @n stripped off
// lib /DEF doesn't support renaming symbols so we have to go through compiling
// a C file with the symbols and building a DLL with renamed exports to get
// the appropriate import library
//
// x64: strip any @ from the symbol names
bool def2implib(bool x64, string f, string dir, string linkopt = null)
{
static auto re = regex(r"@?([a-zA-Z0-9_]+)(@[0-9]*)");
char[] content = cast(char[])std.file.read(f);
auto pos = content.indexOf("EXPORTS");
if (pos < 0)
return false;

char[] def = content[0..pos];
char[] csrc;
bool[string] written;
auto lines = content[pos..$].splitLines;
foreach(line; lines)
{
line = line.strip;
if (line.length == 0 || line[0] == ';')
continue;
const(char)[] sym;
char[] cline;
auto m = matchFirst(line, re);
if (m)
{
if (x64)
def ~= m[1] ~ "\n";
else
def ~= m[0] ~ "=" ~ m[1] ~ "\n";
sym = m[1];
cline = "void " ~ m[1] ~ "() {}\n";
}
else
{
def ~= line ~ "\n";
if (line.endsWith(" DATA"))
{
sym = strip(line[0..$-5]);
cline = "int " ~ sym ~ ";\n";
}
else
{
auto idx = line.indexOf('=');
if (idx > 0)
sym = line[idx+1 .. $].strip;
else
sym = line;
cline = "void " ~ sym ~ "() {}\n";
}
}
if(sym.length && sym !in written)
{
csrc ~= cline;
written[sym.idup] = true;
}
}
string base = stripExtension(baseName(f));
string dirbase = dir ~ base;
std.file.write(dirbase ~ ".def", def);
std.file.write(dirbase ~ ".c", csrc);

runShell("cl /c /Fo" ~ dirbase ~ ".obj " ~ dirbase ~ ".c");
runShell("link /NOD /NOENTRY /DLL " ~ dirbase ~ ".obj /out:" ~ dirbase ~ ".dll /def:" ~ dirbase ~ ".def" ~ linkopt);

// cleanup
std.file.remove(dirbase ~ ".def");
std.file.remove(dirbase ~ ".c");
std.file.remove(dirbase ~ ".obj");
std.file.remove(dirbase ~ ".dll");
std.file.remove(dirbase ~ ".exp");
return true;
}

void buildLibs(bool x64, string defdir, string dir)
{
mkdirRecurse(dir);

//goto LnoDef;
foreach(f; std.file.dirEntries(defdir, SpanMode.shallow))
if (extension(f).toLower == ".def")
def2implib(x64, f, dir);
foreach(f; std.file.dirEntries(defdir ~ "/directx", SpanMode.shallow))
if (extension(f).toLower == ".def")
def2implib(x64, f, dir);

version(DDK) // disable for now
{
mkdirRecurse(dir ~ ddk);
foreach(f; std.file.dirEntries(defdir ~ "/ddk", SpanMode.shallow))
if (extension(f).toLower == ".def")
def2implib(x64, f, dir ~ "ddk/");
}
}

void buildMsvcrt(bool x64, string dir, string msvcdef)
{
string arch = x64 ? "x64" : "x86";
string lib = "lib /MACHINE:" ~ arch ~ " ";
string msvcrtlib = "msvcrt100.lib";

// build msvcrt.lib for VS2010
runShell("cl /EP -D__MSVCRT_VERSION__=0x10000000UL -D__DLLNAME__=msvcr100 " ~ msvcdef ~ " >" ~ dir ~ "msvcrt.def");
runShell(lib ~ "/OUT:" ~ dir ~ msvcrtlib ~ " /DEF:" ~ dir ~ "msvcrt.def"); // no translation necessary
runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_stub0.obj /D_APPTYPE=0 msvcrt_stub.c");
runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_stub1.obj /D_APPTYPE=1 msvcrt_stub.c");
runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_stub2.obj /D_APPTYPE=2 msvcrt_stub.c");
runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_data.obj msvcrt_data.c");
runShell("cl /c /Zl /Fo" ~ dir ~ "msvcrt_atexit.obj msvcrt_atexit.c");
auto files = ["msvcrt_stub0.obj", "msvcrt_stub1.obj", "msvcrt_stub2.obj", "msvcrt_data.obj", "msvcrt_atexit.obj" ];
if (!x64)
{
runShell("ml /c /Fo" ~ dir ~ "msvcrt_abs.obj msvcrt_abs.asm");
files ~= "msvcrt_abs.obj";
}
auto objs = files.map!(a => dir ~ a).join(" ");
runShell(lib ~ dir ~ msvcrtlib ~ " " ~ objs);

// create oldnames.lib (expected by dmd)
runShell("cl /c /Zl /Fo" ~ dir ~ "oldnames.obj oldnames.c");
runShell(lib ~ "/OUT:" ~ dir ~ "oldnames.lib " ~ dir ~ "oldnames.obj");

// create empty uuid.lib (expected by dmd, but UUIDs already in druntime)
std.file.write(dir ~ "empty.c", "");
runShell("cl /c /Zl /Fo" ~ dir ~ "uuid.obj " ~ dir ~ "empty.c");
runShell(lib ~ "/OUT:" ~ dir ~ "uuid.lib " ~ dir ~ "uuid.obj");

foreach(f; files)
std.file.remove(dir ~ f);
std.file.remove(dir ~ stripExtension(msvcrtlib) ~ ".exp");
std.file.remove(dir ~ "msvcrt.def");
std.file.remove(dir ~ "oldnames.obj");
std.file.remove(dir ~ "uuid.obj");
std.file.remove(dir ~ "empty.c");
}

void main(string[] args)
{
bool x64 = (args.length > 1 && args[1] == "x64");
string defdir = (args.length > 2 ? args[2] : "def");
string outdir = x64 ? "lib64/" : "lib32mscoff/";
if (args.length > 3)
outdir = args[3] ~ "/";
string msvcdef = (args.length > 4 ? args[4] : "msvcrt.def.in");

buildLibs(x64, defdir, outdir);
buildMsvcrt(x64, outdir, msvcdef);
}
Loading