diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index b88723c18..0654595e9 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -105,7 +105,6 @@ * [offsetof](syntax_and_semantics/offsetof.md) * [Uninitialized variable declaration](syntax_and_semantics/declare_var.md) * [Compile-time flags](syntax_and_semantics/compile_time_flags.md) - * [Cross-compilation](syntax_and_semantics/cross-compilation.md) * [C bindings](syntax_and_semantics/c_bindings/README.md) * [lib](syntax_and_semantics/c_bindings/lib.md) * [fun](syntax_and_semantics/c_bindings/fun.md) @@ -131,7 +130,9 @@ * [GitHub Actions](guides/ci/gh-actions.md) * [Travis CI](guides/ci/travis.md) * [CircleCI](guides/ci/circleci.md) - * [Static Linking](guides/static_linking.md) + * Compilation + * [Static Linking](guides/static_linking.md) + * [Cross-compilation](guides/compilation/cross-compilation.md) * [Database](database/README.md) * [Connection](database/connection.md) * [Connection pool](database/connection_pool.md) diff --git a/docs/guides/compilation/cross-compilation.md b/docs/guides/compilation/cross-compilation.md new file mode 100644 index 000000000..73586a5d0 --- /dev/null +++ b/docs/guides/compilation/cross-compilation.md @@ -0,0 +1,90 @@ +# Cross-compilation + +Crystal supports a basic form of [cross compilation](http://en.wikipedia.org/wiki/Cross_compiler). + +## Preparation + +Cross-compilation depends on `libcrystal` being present on the target system. It can be built by following these steps: + +* Download the Crystal source code on the target machine. +* Run `make libcrystal` in the source directory. + +This produces `ext/src/libcrystal.a`. + + +## Compiling + +The compiler executable provides two flags: + +* `--cross-compile`: When given enables cross compilation mode +* `--target`: the [LLVM Target Triple](http://llvm.org/docs/LangRef.html#target-triple) to use and set the default [compile-time flags](../../syntax_and_semantics/compile_time_flags.md) from + +The `--target` flags can be determined by executing `gcc -dumpmachine` on the target system. (e.g. 'x86_64-unknown-linux-gnu') + +Any compile-time flags not set implicitly through `--target`, can be specified with the `-D` command line flag. + +Using these two flags, it is possible to compile a program on a Mac that will run on Linux, like this: + +```bash +crystal build your_program.cr --cross-compile --target "x86_64-unknown-linux-gnu" +``` + +This will generate a `.o` ([Object file](http://en.wikipedia.org/wiki/Object_file)) and will print a line with a command to execute on the target system. For example: + +```bash +cc your_program.o -o your_program -lpcre -lgc /local/crystal/src/ext/libcrystal.a +``` + +The command above can be executed on the target system, once the `.o` file has been copied over. The reference to `libcrystal.a` may need to be adjusted to match the location that `libcrystal` was compiled to, as per the preparation step. + +This procedure is usually done with the compiler itself to port it to new platforms where a compiler is not yet available. Because in order to compile a Crystal compiler, an older Crystal compiler is required, the only two ways to generate a compiler for a system where there is no compiler yet are: + +* Checkout the latest version of the compiler written in Ruby, then use that compiler to compile all subsequent versions of the compiler until the current version is reached. +* Create a `.o` file for the target system, and use it to create a compiler. + +The first alternative is long and cumbersome, while the second one is much easier. + +Cross-compiling can be done for other executables, but its main target is the compiler. If Crystal is not available in some system, it can theoretically be cross-compiled for that system. + +## Troubleshooting libraries + +The cross-compilation step will generate a command with numerous flags, many of these refer to the libraries that need to be included when compiling a program. +If the libraries are not present on the target system, the compilation will fail and complain about the respective flags. +To fix this you need to make the missing libraries available for linking on the target system. + +## Example of cross-compiling + +Here's an example of how to cross compile a crystal app on a host machine and then transfering it to the target machine and compiles the last bits there: + +```bash +#!/bin/bash -eu + +srcfile=$1 +target_host=$2 +taret_triple=$3 + +object_file="$(basename $srcfile).o" + +# On host machine: + +# 1. Build objectfile and capture linker command +linker_command=$(crystal build --cross-compile --target=$target_triple --release -o "$object_file" "$srcfile") + +# 2. Upload the object file to the target machine +scp "$object_file" "$target_host":. +rm "$object_file" + +# On target machine: + +# 1. Build libcrystal +ssh "$target_host" /bin/sh -c 'git clone https://github.com/crystal-lang/crystal.git \ + && cd crystal && make libcrystal \ + && sudo mkdir -p /usr/share/crystal/src/ext \ + && sudo cp src/ext/libcrystal.a /usr/share/crystal/src/ext/' + +# 2. Install dependencies (this assumes a debian/ubuntu target OS) +ssh "$target_host" sudo apt-get install -y libpcre3-dev libgc-dev libevent-dev + +# 3. Link the object file with the command printed from `crystal build --cross-compile` +ssh "$target_host" "$linker_command" +``` diff --git a/docs/syntax_and_semantics/cross-compilation.md b/docs/syntax_and_semantics/cross-compilation.md deleted file mode 100644 index 032c21260..000000000 --- a/docs/syntax_and_semantics/cross-compilation.md +++ /dev/null @@ -1,35 +0,0 @@ -# Cross-compilation - -Crystal supports a basic form of [cross compilation](http://en.wikipedia.org/wiki/Cross_compiler). - -In order to achieve this, the compiler executable provides two flags: - -* `--cross-compile`: When given enables cross compilation mode -* `--target`: the [LLVM Target Triple](http://llvm.org/docs/LangRef.html#target-triple) to use and set the default [compile-time flags](compile_time_flags.md) from - -To get the `--target` flags you can execute `llvm-config --host-target` using an installed LLVM 3.5. For example on a Linux it could say "x86_64-unknown-linux-gnu". - -If you need to set any compile-time flags not set implicitly through `--target`, you can use the `-D` command line flag. - -Using these two, we can compile a program in a Mac that will run on that Linux like this: - -```bash -crystal build your_program.cr --cross-compile --target "x86_64-unknown-linux-gnu" -``` - -This will generate a `.o` ([Object file](http://en.wikipedia.org/wiki/Object_file)) and will print a line with a command to execute on the system we are trying to cross-compile to. For example: - -```bash -cc your_program.o -o your_program -lpcre -lrt -lm -lgc -lunwind -``` - -You must copy this `.o` file to that system and execute those commands. Once you do this the executable will be available in that target system. - -This procedure is usually done with the compiler itself to port it to new platforms where a compiler is not yet available. Because in order to compile a Crystal compiler we need an older Crystal compiler, the only two ways to generate a compiler for a system where there isn't a compiler yet are: - -* We checkout the latest version of the compiler written in Ruby, and from that compiler we compile the next versions until the current one. -* We create a `.o` file in the target system and from that file we create a compiler. - -The first alternative is long and cumbersome, while the second one is much easier. - -Cross-compiling can be done for other executables, but its main target is the compiler. If Crystal isn't available in some system you can try cross-compiling it there. diff --git a/docs/using_the_compiler/README.md b/docs/using_the_compiler/README.md index 3c41e7390..94ad72b9c 100644 --- a/docs/using_the_compiler/README.md +++ b/docs/using_the_compiler/README.md @@ -141,7 +141,7 @@ Hello Crystal! **Common options:** -* `--cross-compile`: Generate a .o file, and print the command to generate an executable to stdout. +* `--cross-compile`: Generate a .o file, and print the command to generate an executable to stdout (see [*Cross Compilation* guide](../guides/compilation/cross-compilation.md)). * `-D FLAG, --define FLAG`: Define a compile-time flag. * `-o `: Define the name of the binary executable. * `--release`: Compile in release mode, doing extra work to apply optimizations to the generated code. diff --git a/mkdocs.yml b/mkdocs.yml index fbdab1c61..87c0b4160 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -34,16 +34,17 @@ plugins: syntax_and_semantics/macros.md: syntax_and_semantics/macros/README.md syntax_and_semantics/annotations.md: syntax_and_semantics/annotations/README.md guides/continuous_integration.md: guides/ci/README.md + syntax_and_semantics/cross-compilation.md: guides/compilation/cross-compilation.md conventions/documenting_code.md: syntax_and_semantics/documenting_code.md markdown_extensions: - admonition - pymdownx.highlight - pymdownx.magiclink + - pymdownx.snippets - pymdownx.superfences - toc: permalink: true - - pymdownx.snippets google_analytics: - UA-42353458-1 @@ -52,7 +53,7 @@ google_analytics: extra_javascript: - assets/vendor/codemirror/codemirror.min.js - assets/vendor/codemirror/mode/crystal/crystal.min.js + - assets/vendor/ansi_up/ansi_up.min.js - assets/vendor/carcin-play/carcin.js - assets/vendor/carcin-play/carcin-play.js - - assets/vendor/ansi_up/ansi_up.min.js - assets/crystal-play.js