Difference between revisions of "Building LDC runtime libraries"

From D Wiki
Jump to: navigation, search
m (Usage for cross-compilation)
m (Usage for cross-compilation: Somewhat modernize Android and Apple examples)
 
(18 intermediate revisions by 3 users not shown)
Line 1: Line 1:
Starting with version 1.4, LDC ships with a small build tool to allow you to recompile the runtime standard library (and optionally the accompanying testrunners) the way you want, [https://github.com/ldc-developers/ldc/blob/master/runtime/ldc-build-runtime.d.in ldc-build-runtime].
+
Starting with version 1.4, LDC ships with a small build tool to allow you to recompile the D runtime and standard library (and optionally the accompanying testrunners) the way you want, [https://github.com/ldc-developers/ldc/blob/master/runtime/ldc-build-runtime.d.in ldc-build-runtime].
  
 
== Use cases ==
 
== Use cases ==
  
* Enabling Link-Time Optimization (LTO) for the runtime libraries by recompiling them with <tt>-flto</tt>. Linking against these may result in significant performance gains and smaller binaries.
+
* Link-Time Optimization (LTO) for the runtime libraries by recompiling with <tt>-flto</tt>, which produces smaller binaries and may show significant performance gains
* Enabling sanitizer checks via <tt>-fsanitize</tt>.
+
* Adding sanitizer checks via <tt>-fsanitize</tt>
* Cross-compilation/linking, as a set of existing druntime/Phobos libraries for the selected target platform is required to cross-compile and link D executables and shared libraries.
+
* Cross-compilation for other platforms, as the D runtime and standard library must be generated for your target platform before you can cross-compile and link D executables and shared libraries
** This scenario also includes porting LDC to a new target platform, i.e., working on the runtime libraries on an arbitrary already supported host platform while possibly patching the host LDC in parallel (ABI etc.) until the runtime libraries can be successfully cross-built to the new target and ideally all testrunners run successfully (in an emulator or natively on the target).
 
  
 
== Prerequisites ==
 
== Prerequisites ==
  
 
* [https://cmake.org/download/ CMake]
 
* [https://cmake.org/download/ CMake]
* Either [https://www.gnu.org/software/make/ Make] or [https://github.com/ninja-build/ninja/releases Ninja] (recommended, enable with <tt>--ninja</tt>)
+
* Either [https://www.gnu.org/software/make/ Make], the default, or [https://github.com/ninja-build/ninja/releases Ninja] (recommended, enable with <tt>--ninja</tt>)
 
* C toolchain (compiler, linker and libraries): gcc, clang, Microsoft Visual C++, …
 
* C toolchain (compiler, linker and libraries): gcc, clang, Microsoft Visual C++, …
  
Line 20: Line 19:
 
* Creating a build directory
 
* Creating a build directory
 
* Downloading & extracting the LDC source archive matching the LDC version
 
* Downloading & extracting the LDC source archive matching the LDC version
* Invoking CMake to generate the Makefile for the runtime libraries
+
* Invoking CMake to generate the Make or Ninja build script for the runtime libraries
* Invoking Make/Ninja to build the runtime libraries
+
* Calling Make or Ninja to build the runtime libraries
 +
 
 +
The runtime libraries end up in the <tt>lib</tt> subdirectory of the build directory, i.e. <tt>./ldc-build-runtime.tmp/lib</tt> by default. You can replace your existing LDC runtime libraries or link against the new libraries by specifying their directory in the LDC command line: <tt>ldc2 … -L-L/path/to/ldc-build-runtime.tmp/lib</tt>.
  
 
== Basic usage ==
 
== Basic usage ==
Line 31: Line 32:
 
</pre>
 
</pre>
  
E.g., to prepare for Link-Time-Optimization between your user code and the runtime libraries, you can recompile the static runtime libraries via:
+
For example, to prepare for link-time optimization between your user code and the static runtime libraries, you can recompile the runtime libraries with:
  
 
<pre>
 
<pre>
ldc-build-runtime --ninja --dFlags="-flto=full" BUILD_SHARED_LIBS=OFF
+
ldc-build-runtime --ninja --dFlags="-flto=thin" BUILD_SHARED_LIBS=OFF
 
</pre>
 
</pre>
  
OSX only: a ThinLTO version of the standard library will result in linker errors due to this issue: https://github.com/ldc-developers/ldc/issues/2312 . (this is not an issue if gold or lld is used)
+
== Solution for common problems ==
 +
 
 +
<li>Cannot check C compiler(CMakeTestCCompiler): Add '''CMAKE_C_COMPILER_WORKS=1''' and it will skip the C compiler check. </li>
  
 
== Usage for cross-compilation ==
 
== Usage for cross-compilation ==
  
<pre>
+
<syntaxhighlight lang=bash>
 
CC=cross-gcc ldc-build-runtime [--ninja] [-j4] [--testrunners] --dFlags="-mtriple=…;…" [--cFlags=…] [--linkerFlags=…] --targetSystem=… …
 
CC=cross-gcc ldc-build-runtime [--ninja] [-j4] [--testrunners] --dFlags="-mtriple=…;…" [--cFlags=…] [--linkerFlags=…] --targetSystem=… …
</pre>
+
</syntaxhighlight>
 +
 
 +
For example, to cross-compile from linux/x64 with glibc to an Alpine linux/x64 container just requires specifying a C cross-compiler and a different cross-compilation triple (install the clang and musl packages in Arch linux to try this out):
 +
 
 +
<syntaxhighlight lang=bash>
 +
CC=musl-clang ldc-build-runtime --dFlags="-mtriple=x86_64-alpine-linux-musl"
 +
</syntaxhighlight>
 +
 
 +
From Linux/x86_64 to Linux/ARM:
 +
 
 +
<syntaxhighlight lang=bash>
 +
CC=arm-linux-gnueabihf-gcc ldc-build-runtime --ninja --dFlags="-mtriple=arm-linux-gnueabihf"
 +
</syntaxhighlight>
 +
 
 +
or to Linux/AArch64, ie 64-bit ARM (here using the <tt>aarch64-linux-gnu-gcc</tt> package in Arch linux):
 +
 
 +
<syntaxhighlight lang=bash>
 +
CC=aarch64-linux-gnu-gcc ldc-build-runtime --ninja --dFlags="-mtriple=aarch64-none-linux-gnu"
 +
</syntaxhighlight>
  
For example, to cross-compile from Linux/x86_64 to Linux/ARM:
+
or to Linux/MIPS32:
  
<pre>
+
<syntaxhighlight lang=bash>
CC=arm-linux-gnueabihf-gcc ldc-build-runtime --ninja --dFlags="-w;-mtriple=arm-linux-gnueabihf" --targetSystem="Linux;UNIX"  
+
CC=mipsel-linux-gcc ldc-build-runtime --ninja --dFlags="-mtriple=mipsel-linux;-mcpu=mips32" --cFlags="-march=mips32"
</pre>
+
</syntaxhighlight>
  
 
From Windows to Linux/ARM, e.g., by using an official [http://gnutoolchains.com/raspberry/ Raspberry PI toolchain]:
 
From Windows to Linux/ARM, e.g., by using an official [http://gnutoolchains.com/raspberry/ Raspberry PI toolchain]:
  
<pre>
+
<syntaxhighlight lang=bash>
 
set CC=arm-linux-gnueabihf-gcc
 
set CC=arm-linux-gnueabihf-gcc
ldc-build-runtime --ninja --dFlags=-w;-mtriple=arm-linux-gnueabihf --targetSystem=Linux;UNIX CMAKE_SYSTEM_NAME=Linux CMAKE_C_COMPILER_WORKS=True BUILD_SHARED_LIBS=OFF
+
ldc-build-runtime --ninja --dFlags=-mtriple=arm-linux-gnueabihf --targetSystem=Linux;UNIX CMAKE_SYSTEM_NAME=Linux CMAKE_C_COMPILER_WORKS=True BUILD_SHARED_LIBS=OFF
</pre>
+
</syntaxhighlight>
 +
 
 +
From Linux, Mac or Windows to Android/AArch64, assuming the [https://developer.android.com/ndk/downloads Android NDK] r26d has been unzipped into <tt>/home/me</tt>:
 +
 
 +
<syntaxhighlight lang=bash>
 +
ldc-build-runtime --ninja \
 +
                  --dFlags="-mtriple=aarch64-linux-android30" \
 +
                  --targetSystem="Android;Linux;UNIX" \
 +
                  CMAKE_TOOLCHAIN_FILE="/home/me/android-ndk-r26d/build/cmake/android.toolchain.cmake" \
 +
                  ANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF \
 +
                  ANDROID_ABI=arm64-v8a \
 +
                  ANDROID_NATIVE_API_LEVEL=30
 +
</syntaxhighlight>
 +
 
 +
Check out the official [https://developer.android.com/ndk/guides/cmake Android NDK CMake guide] for possible values of the <tt>ANDROID_*</tt> variables, e.g., to target other architectures (and make sure to adapt the <tt>-mtriple</tt> flag in that case). For full instructions on Android cross-compilation, [[Build D for Android|see the Android page]]. It also shows examples of using ldc with the newly generated runtime libraries to compile your own code.
  
Cross-compiling to Android/ARM using the Android NDK is more involved, so ldc-build-runtime features a target preset for it. First, you set the path to your NDK and cross-compiler, and then you simply specify the target preset (while still being able to tweak the individual flags):
+
From macOS/x64 to macOS/arm64:
  
<pre>
+
<syntaxhighlight lang=bash>
export NDK=/path/to/your/android-ndk-r15c
+
ldc-build-runtime --ninja \
export CC=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
+
                  --dFlags="-mtriple=arm64-apple-macos11.0" \
ldc-build-runtime --ninja [--testrunners] --targetPreset=Android-arm
+
                  CMAKE_OSX_ARCHITECTURES=arm64 \
</pre>
+
                  CMAKE_OSX_DEPLOYMENT_TARGET=11.0
 +
</syntaxhighlight>
  
----
+
or to iOS/arm64:
  
 +
<syntaxhighlight lang=bash>
 +
ldc-build-runtime --ninja \
 +
                  --dFlags="-mtriple=arm64-apple-ios12.0" \
 +
                  CMAKE_SYSTEM_NAME=iOS \
 +
                  CMAKE_OSX_ARCHITECTURES=arm64 \
 +
                  CMAKE_OSX_DEPLOYMENT_TARGET=12.0
 +
</syntaxhighlight>
 +
 
[[Category:LDC]]
 
[[Category:LDC]]

Latest revision as of 20:40, 21 May 2024

Starting with version 1.4, LDC ships with a small build tool to allow you to recompile the D runtime and standard library (and optionally the accompanying testrunners) the way you want, ldc-build-runtime.

Use cases

  • Link-Time Optimization (LTO) for the runtime libraries by recompiling with -flto, which produces smaller binaries and may show significant performance gains
  • Adding sanitizer checks via -fsanitize
  • Cross-compilation for other platforms, as the D runtime and standard library must be generated for your target platform before you can cross-compile and link D executables and shared libraries

Prerequisites

  • CMake
  • Either Make, the default, or Ninja (recommended, enable with --ninja)
  • C toolchain (compiler, linker and libraries): gcc, clang, Microsoft Visual C++, …

How it works

If run without special command-line options, ldc-build-runtime automates:

  • Creating a build directory
  • Downloading & extracting the LDC source archive matching the LDC version
  • Invoking CMake to generate the Make or Ninja build script for the runtime libraries
  • Calling Make or Ninja to build the runtime libraries

The runtime libraries end up in the lib subdirectory of the build directory, i.e. ./ldc-build-runtime.tmp/lib by default. You can replace your existing LDC runtime libraries or link against the new libraries by specifying their directory in the LDC command line: ldc2 … -L-L/path/to/ldc-build-runtime.tmp/lib.

Basic usage

The primary aim is to allow specifying additional compiler/linker command-line options and customizing CMake variables.
Run ldc-build-runtime -h for the full list of command-line options.

ldc-build-runtime [--ninja] [-j4] [--testrunners] [--dFlags=…] [--cFlags=…] [--linkerFlags=…] [CMAKE_VAR1=value1] [CMAKE_VAR2=value2 …]

For example, to prepare for link-time optimization between your user code and the static runtime libraries, you can recompile the runtime libraries with:

ldc-build-runtime --ninja --dFlags="-flto=thin" BUILD_SHARED_LIBS=OFF

Solution for common problems

  • Cannot check C compiler(CMakeTestCCompiler): Add CMAKE_C_COMPILER_WORKS=1 and it will skip the C compiler check.
  • Usage for cross-compilation

    CC=cross-gcc ldc-build-runtime [--ninja] [-j4] [--testrunners] --dFlags="-mtriple=…;…" [--cFlags=] [--linkerFlags=] --targetSystem=… …
    

    For example, to cross-compile from linux/x64 with glibc to an Alpine linux/x64 container just requires specifying a C cross-compiler and a different cross-compilation triple (install the clang and musl packages in Arch linux to try this out):

    CC=musl-clang ldc-build-runtime --dFlags="-mtriple=x86_64-alpine-linux-musl"
    

    From Linux/x86_64 to Linux/ARM:

    CC=arm-linux-gnueabihf-gcc ldc-build-runtime --ninja --dFlags="-mtriple=arm-linux-gnueabihf"
    

    or to Linux/AArch64, ie 64-bit ARM (here using the aarch64-linux-gnu-gcc package in Arch linux):

    CC=aarch64-linux-gnu-gcc ldc-build-runtime --ninja --dFlags="-mtriple=aarch64-none-linux-gnu"
    

    or to Linux/MIPS32:

    CC=mipsel-linux-gcc ldc-build-runtime --ninja --dFlags="-mtriple=mipsel-linux;-mcpu=mips32" --cFlags="-march=mips32"
    

    From Windows to Linux/ARM, e.g., by using an official Raspberry PI toolchain:

    set CC=arm-linux-gnueabihf-gcc
    ldc-build-runtime --ninja --dFlags=-mtriple=arm-linux-gnueabihf --targetSystem=Linux;UNIX CMAKE_SYSTEM_NAME=Linux CMAKE_C_COMPILER_WORKS=True BUILD_SHARED_LIBS=OFF
    

    From Linux, Mac or Windows to Android/AArch64, assuming the Android NDK r26d has been unzipped into /home/me:

    ldc-build-runtime --ninja \
                      --dFlags="-mtriple=aarch64-linux-android30" \
                      --targetSystem="Android;Linux;UNIX" \
                      CMAKE_TOOLCHAIN_FILE="/home/me/android-ndk-r26d/build/cmake/android.toolchain.cmake" \
                      ANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF \
                      ANDROID_ABI=arm64-v8a \
                      ANDROID_NATIVE_API_LEVEL=30
    

    Check out the official Android NDK CMake guide for possible values of the ANDROID_* variables, e.g., to target other architectures (and make sure to adapt the -mtriple flag in that case). For full instructions on Android cross-compilation, see the Android page. It also shows examples of using ldc with the newly generated runtime libraries to compile your own code.

    From macOS/x64 to macOS/arm64:

    ldc-build-runtime --ninja \
                      --dFlags="-mtriple=arm64-apple-macos11.0" \
                      CMAKE_OSX_ARCHITECTURES=arm64 \
                      CMAKE_OSX_DEPLOYMENT_TARGET=11.0
    

    or to iOS/arm64:

    ldc-build-runtime --ninja \
                      --dFlags="-mtriple=arm64-apple-ios12.0" \
                      CMAKE_SYSTEM_NAME=iOS \
                      CMAKE_OSX_ARCHITECTURES=arm64 \
                      CMAKE_OSX_DEPLOYMENT_TARGET=12.0