├── .gitignore ├── .gn ├── BUILD.gn ├── README.md ├── build ├── BUILDCONFIG.gn ├── config │ └── compiler │ │ └── BUILD.gn └── toolchain │ └── clang │ └── BUILD.gn ├── example ├── BUILD.gn ├── another_example.c ├── another_example.h └── example.cc └── tools ├── setup_gn.sh └── setup_sdk.sh /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | sdk/ 3 | -------------------------------------------------------------------------------- /.gn: -------------------------------------------------------------------------------- 1 | 2 | buildconfig = "//build/BUILDCONFIG.gn" 3 | -------------------------------------------------------------------------------- /BUILD.gn: -------------------------------------------------------------------------------- 1 | group("default") { 2 | deps = [ 3 | "example", 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Raspberry Pi Cross Compilation SDK 2 | ================================== 3 | 4 | Clang 6 based toolchain and GN buildroot for setting up a cross-compilation environment for the Raspberry Pi. 5 | 6 | Prerequisites 7 | ------------- 8 | 9 | * A Mac or Linux host and a Raspberry Pi. 10 | 11 | Usage for Raspberry Pi 12 | ---------------------- 13 | 14 | * Download the prepared toolchain, sysroot and related tools to the `out` directory `./tools/setup_sdk.sh`. 15 | * This takes a while and downloads upto 1 GB of data from cloud storage. 16 | * Prepare the build output directory `out` with paths to your toolchain using `./tools/setup_gn.sh`. 17 | * Build using `ninja -C out` on your host. 18 | * Hack and repeat. 19 | * Push your executable to the Raspberry Pi and run. 20 | * You should probably mount the `out` directory to the remote Raspberry Pi using SSHFS. That way, the build artifacts automatically end up getting pushed to the Pi. 21 | -------------------------------------------------------------------------------- /build/BUILDCONFIG.gn: -------------------------------------------------------------------------------- 1 | set_default_toolchain("//build/toolchain/clang") 2 | 3 | set_defaults("executable") { 4 | configs = [ "//build/config/compiler" ] 5 | } 6 | -------------------------------------------------------------------------------- /build/config/compiler/BUILD.gn: -------------------------------------------------------------------------------- 1 | config("compiler") { 2 | # Defaults that will be filled in later below. 3 | cflags = [] 4 | cflags_c = [] 5 | cflags_cc = [] 6 | ldflags = [] 7 | 8 | cflags_c += [ "-std=c99" ] 9 | 10 | cflags_cc += [ "-std=c++14" ] 11 | 12 | libs = [ 13 | "m", 14 | "stdc++", 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /build/toolchain/clang/BUILD.gn: -------------------------------------------------------------------------------- 1 | declare_args() { 2 | # The path to functional Clang toolchain capable of building the target triple. 3 | toolchain_path = "" 4 | 5 | # The path to the target system sysroot. 6 | sysroot_path = "" 7 | 8 | # The target. For example: "arm-linux-gnueabihf" for Raspberry Pi. 9 | target_triple = "" 10 | 11 | # Path to extra system inlcude directories relative to the sysroot. For example: "/opt/vc/include" on the Raspberry Pi. 12 | extra_system_include_dirs = [] 13 | 14 | # Path to extra system library directories relative to the sysroot. For example: "/opt/vc/lib" on the Raspberry Pi. 15 | extra_system_lib_dirs = [] 16 | } 17 | 18 | toolchain("clang") { 19 | assert(toolchain_path != "", "Toolchain must be specified") 20 | assert(sysroot_path != "", "Sysroot must be specified") 21 | assert(target_triple != "", "Target triple must be specified") 22 | 23 | # Setup path to the tools to invoke 24 | cc = "${toolchain_path}/bin/clang" 25 | cxx = "${toolchain_path}/bin/clang++" 26 | ld = "${toolchain_path}/bin/clang" 27 | ar = "${toolchain_path}/bin/$target_triple-ar" 28 | 29 | # Setup the target triple, this needs is required for all tool invocations. 30 | target_triple_command = "--target=$target_triple" 31 | sysroot_command = "--sysroot $sysroot_path" 32 | 33 | # Add extra headers search directories for folders relative to sysroot. 34 | extra_system_include_dirs_string = "-isysroot $sysroot_path" 35 | foreach(extra_system_include_dir, extra_system_include_dirs) { 36 | extra_system_include_dirs_string = "$extra_system_include_dirs_string -iwithsysroot $extra_system_include_dir" 37 | } 38 | 39 | # Add extra library search paths for folders relative to sysroot. 40 | extra_system_lib_dirs_string = "" 41 | foreach(extra_system_lib_dir, extra_system_lib_dirs) { 42 | extra_system_lib_dirs_string = 43 | "$extra_system_lib_dirs_string -L$sysroot_path/$extra_system_lib_dir" 44 | } 45 | 46 | # Common GN verbiage. 47 | lib_switch = "-l" 48 | lib_dir_switch = "-L" 49 | 50 | # Common description prefixes in non-verbose invocation. 51 | pretty_build_prefix = "🔨 " 52 | pretty_link_prefix = "⛓️ " 53 | 54 | tool("cc") { 55 | depfile = "{{output}}.deps" 56 | command = "$cc -o {{output}} -MMD -MF $depfile -c $target_triple_command $sysroot_command $extra_system_include_dirs_string {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} {{source}}" 57 | outputs = [ 58 | "{{target_out_dir}}/{{target_output_name}}/objects/{{source_name_part}}.o", 59 | ] 60 | depsformat = "gcc" 61 | description = "$pretty_build_prefix CC: {{source_name_part}}" 62 | } 63 | 64 | tool("cxx") { 65 | depfile = "{{output}}.deps" 66 | command = "$cxx -o {{output}} -MMD -MF $depfile -c $target_triple_command $sysroot_command $extra_system_include_dirs_string {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} {{source}}" 67 | outputs = [ 68 | "{{target_out_dir}}/{{target_output_name}}/objects/{{source_name_part}}.o", 69 | ] 70 | depsformat = "gcc" 71 | description = "$pretty_build_prefix CXX: {{source_name_part}}" 72 | } 73 | 74 | tool("alink") { 75 | rspfile = "{{output}}.rsp" 76 | command = "rm -f {{output}} && $ar rcs {{output}} @$rspfile" 77 | description = "$pretty_link_prefix Archive: {{output}}" 78 | rspfile_content = "{{inputs}}" 79 | outputs = [ 80 | "{{target_out_dir}}/{{target_output_name}}{{output_extension}}", 81 | ] 82 | default_output_extension = ".a" 83 | output_prefix = "lib" 84 | } 85 | 86 | tool("solink") { 87 | outfile = "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" 88 | rspfile = "{{output}}.rsp" 89 | rspfile_content = "{{inputs}}" 90 | command = "$ld -o $outfile $target_triple_command $sysroot_command $extra_system_lib_dirs_string -shared {{ldflags}} {{solibs}} {{libs}} @$rspfile" 91 | description = "$pretty_link_prefix Shared Library: {{output}}" 92 | outputs = [ 93 | outfile, 94 | ] 95 | default_output_extension = ".so" 96 | output_prefix = "lib" 97 | } 98 | 99 | tool("link") { 100 | outfile = "{{target_out_dir}}/{{target_output_name}}/executables/{{target_output_name}}" 101 | rspfile = "$outfile.rsp" 102 | rspfile_content = "{{inputs}}" 103 | command = "$ld -o $outfile $target_triple_command $sysroot_command $extra_system_lib_dirs_string {{ldflags}} {{solibs}} {{libs}} @$rspfile" 104 | outputs = [ 105 | outfile, 106 | ] 107 | description = "$pretty_link_prefix Link Executable: {{target_output_name}}" 108 | } 109 | 110 | tool("stamp") { 111 | command = "touch {{output}}" 112 | description = "$pretty_build_prefix Stamp: {{output}}" 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /example/BUILD.gn: -------------------------------------------------------------------------------- 1 | static_library("contrived_example_of_static_library") { 2 | sources = [ 3 | "another_example.c", 4 | "another_example.h", 5 | "example.cc", 6 | ] 7 | } 8 | 9 | executable("example") { 10 | deps = [ 11 | ":contrived_example_of_static_library", 12 | ] 13 | 14 | libs = [ 15 | "rt", 16 | "pthread", 17 | "dl", 18 | "bcm_host", 19 | "vcos", 20 | "vchiq_arm", 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /example/another_example.c: -------------------------------------------------------------------------------- 1 | #include "another_example.h" 2 | 3 | #include 4 | 5 | void PrintExampleString() { printf("Another Hello World.\n"); } 6 | -------------------------------------------------------------------------------- /example/another_example.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | void PrintExampleString(); 4 | -------------------------------------------------------------------------------- /example/example.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | extern "C" { 5 | #include "another_example.h" 6 | } 7 | 8 | int main(int argc, char const *argv[]) { 9 | std::cout << "Hello World." << std::endl; 10 | PrintExampleString(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /tools/setup_gn.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 6 | SDK_DIR="${SCRIPT_DIR}/../sdk" 7 | OUT_DIR="${SCRIPT_DIR}/../out" 8 | ARGS_GN="${OUT_DIR}/args.gn" 9 | 10 | mkdir -p "${OUT_DIR}" 11 | rm -f "${ARGS_GN}" 12 | 13 | echo "toolchain_path = \"${SDK_DIR}/toolchain\"" > "${ARGS_GN}" 14 | echo "sysroot_path = \"${SDK_DIR}/sysroot\"" >> "${ARGS_GN}" 15 | echo "target_triple = \"arm-linux-gnueabihf\"" >> "${ARGS_GN}" 16 | echo "extra_system_include_dirs = [\"/opt/vc/include\"]" >> "${ARGS_GN}" 17 | echo "extra_system_lib_dirs = [\"/opt/vc/lib\"]" >> "${ARGS_GN}" 18 | 19 | "${SDK_DIR}/gn" gen "${OUT_DIR}" 20 | -------------------------------------------------------------------------------- /tools/setup_sdk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | ReportError() { 6 | echo "$@" 1>&2; 7 | } 8 | 9 | TOOCHAIN_NAME="" 10 | GN_PLATFORM_NAME="" 11 | 12 | if [ "$(uname)" == "Darwin" ]; then 13 | TOOLCHAIN_NAME="darwin-x64" 14 | GN_PLATFORM_NAME="mac" 15 | elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then 16 | TOOLCHAIN_NAME="linux-x64" 17 | GN_PLATFORM_NAME="linux64" 18 | else 19 | ReportError "This platform is not supported. Supported platforms are Darwin or Linux." 20 | exit -1 21 | fi 22 | 23 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 24 | SDK_DIR="${SCRIPT_DIR}/../sdk/" 25 | 26 | rm -rf "${SDK_DIR}" 27 | mkdir -p "${SDK_DIR}" 28 | 29 | echo "Settng up Toolchain..." 30 | wget -O "${SDK_DIR}/toolchain.tar.gz" "https://public.chinmaygarde.com/xcompile/toolchain/${TOOLCHAIN_NAME}.tar.gz" 31 | tar -xzvf "${SDK_DIR}/toolchain.tar.gz" -C "${SDK_DIR}" 32 | rm "${SDK_DIR}/toolchain.tar.gz" 33 | mv "${SDK_DIR}/${TOOLCHAIN_NAME}" "${SDK_DIR}/toolchain" 34 | 35 | echo "Setting up Sysroot..." 36 | wget -O "${SDK_DIR}/sysroot.tar.gz" "https://public.chinmaygarde.com/xcompile/sysroot.tar.gz" 37 | tar -xzvf "${SDK_DIR}/sysroot.tar.gz" -C "${SDK_DIR}" 38 | rm "${SDK_DIR}/sysroot.tar.gz" 39 | 40 | echo "Setting up GN..." 41 | wget -O "${SDK_DIR}/gn" "https://storage.googleapis.com/fuchsia-build/fuchsia/gn/${GN_PLATFORM_NAME}/216b1a3e072f9e531abcf79600fa52fd729b1262" 42 | chmod +x "${SDK_DIR}/gn" 43 | --------------------------------------------------------------------------------