defmodule System.Env do @path "PATH" @ld_library_path "LD_LIBRARY_PATH" def path_add(p) do System.put_env(@path, "#{path()}:#{p}") end def ld_library_path_add(p) do System.put_env(@ld_library_path, "#{ld_library_path()}:#{p}") end def path do System.get_env(@path) end def ld_library_path do System.get_env(@ld_library_path) end end defmodule Utils do def crosscompile(gcc_path, system_path) do gcc = gcc_path |> Path.join("*gcc") |> Path.wildcard |> List.first gcc || Mix.raise(""" gcc should have been found in \"#{gcc_path}\", but wasn't. \"#{system_path}\" is partial or corrupt and may need to be deleted. """) String.replace_suffix(gcc, "-gcc", "") end end system_path = System.get_env("NERVES_SYSTEM") || Mix.raise("You must set NERVES_SYSTEM to the system directory prior to requiring this file") sdk_sysroot = Path.join(system_path, "staging") {_toolchain_path, crosscompile} = if File.dir?(Path.join(system_path, "host")) do # Grab the toolchain from a Buildroot output directory toolchain_path = Path.join(system_path, "host") gcc_path = Path.join(toolchain_path, "usr/bin") crosscompile = Utils.crosscompile(gcc_path, system_path) System.put_env("PKG_CONFIG", Path.join(toolchain_path, "usr/bin/pkg-config")) System.put_env("PKG_CONFIG_SYSROOT_DIR", sdk_sysroot) System.put_env("PKG_CONFIG_LIBDIR", Path.join(sdk_sysroot, "usr/lib/pkgconfig")) System.put_env("PERLLIB", Path.join(toolchain_path, "usr/lib/perl")) Path.join(toolchain_path, "usr/bin") |> System.Env.path_add Path.join(toolchain_path, "usr/sbin") |> System.Env.path_add Path.join(toolchain_path, "bin") |> System.Env.path_add Path.join(toolchain_path, "usr/lib") |> System.Env.ld_library_path_add {toolchain_path, crosscompile} else # Not a BR Local Provider build toolchain_path = System.get_env("NERVES_TOOLCHAIN") || Mix.raise("You must set NERVES_TOOLCHAIN to the toolchain directory prior to requiring this file") gcc_path = Path.join(toolchain_path, "bin") # Find the crosscompilers crosscompile = Utils.crosscompile(gcc_path, system_path) # Add toolchain bin to path Path.join(toolchain_path, "bin") |> System.Env.path_add {toolchain_path, crosscompile} end System.put_env("NERVES_SDK_IMAGES", Path.join(system_path, "images")) System.put_env("NERVES_SDK_SYSROOT", sdk_sysroot) system_include_path = system_path |> Path.join("staging/usr/include") unless File.dir?(Path.join(system_path, "staging")) do Mix.raise("ERROR: It looks like the system hasn't been built!") end System.put_env("CROSSCOMPILE", crosscompile) erts_dir = Path.join(sdk_sysroot, "usr/lib/erlang/erts-*") |> Path.wildcard |> List.first System.put_env("ERTS_DIR", erts_dir) erl_interface_dir = Path.join(sdk_sysroot, "/usr/lib/erlang/lib/erl_interface-*") |> Path.wildcard |> List.first System.put_env("ERL_INTERFACE_DIR", erl_interface_dir) erl_lib_dir = Path.join(sdk_sysroot, "/usr/lib/erlang") System.put_env("REBAR_PLT_DIR", erl_lib_dir) System.put_env("ERL_LIB_DIR", erl_lib_dir) erl_system_lib_dir = Path.join(erl_lib_dir, "/lib") System.put_env("ERL_SYSTEM_LIB_DIR", erl_system_lib_dir) # Override Make implicit variables with their crosscompile versions # https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html System.put_env("AR", "#{crosscompile}-ar") System.put_env("AS", "#{crosscompile}-as") System.put_env("CC", "#{crosscompile}-gcc") System.put_env("CXX", "#{crosscompile}-g++") System.put_env("LD", "#{crosscompile}-ld") System.put_env("STRIP", "#{crosscompile}-strip") # Set defaults for compiler flags System.put_env("CFLAGS", "-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -pipe -Os -I#{system_include_path}") System.put_env("CXXFLAGS", "-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -pipe -Os -I#{system_include_path}") System.put_env("LDFLAGS", "--sysroot=#{sdk_sysroot}") System.put_env("ERL_CFLAGS", "-I#{erts_dir}/include -I#{erl_interface_dir}/include") System.put_env("ERL_LDFLAGS", "-L#{erts_dir}/lib -L#{erl_interface_dir}/lib -lerts -lerl_interface -lei") # Qt/Qmake support qmakespec_dir = Path.join(system_path, "staging/mkspecs/devices/linux-buildroot-g++") if File.dir?(qmakespec_dir) do System.put_env("QMAKESPEC", qmakespec_dir) end # Rebar naming System.put_env("REBAR_TARGET_ARCH", Path.basename(crosscompile)) System.put_env("ERL_EI_LIBDIR", Path.join(erl_interface_dir, "lib")) System.put_env("ERL_EI_INCLUDE_DIR", Path.join(erl_interface_dir, "include")) # erlang.mk naming System.put_env("ERTS_INCLUDE_DIR", "#{erts_dir}/include") System.put_env("ERL_INTERFACE_LIB_DIR", Path.join(erl_interface_dir, "lib")) System.put_env("ERL_INTERFACE_INCLUDE_DIR", Path.join(erl_interface_dir, "include")) host_erl_major_ver = :erlang.system_info(:otp_release) |> to_string [target_erl_major_version | _] = sdk_sysroot |> Path.join("/usr/lib/erlang/releases/*/OTP_VERSION") |> Path.wildcard |> List.first |> File.read! |> String.trim |> String.split(".") # Check to see if the system major version of ERL and the target major version match if host_erl_major_ver != target_erl_major_version do Mix.raise """ Major version mismatch between host and target Erlang/OTP versions Host version: #{host_erl_major_ver} Target version: #{target_erl_major_version} This will likely cause Erlang code compiled for the target to fail in unexpected ways. Install an Erlang OTP release that matches the target version before continuing. """ end