-
Notifications
You must be signed in to change notification settings - Fork 0
/
nerves_env.exs
220 lines (173 loc) · 7.12 KB
/
nerves_env.exs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
defmodule System.Env do
@path "PATH"
@ld_library_path "LD_LIBRARY_PATH"
def path_add(p) do
System.put_env(@path, "#{p}:#{path()}")
end
def ld_library_path_add(p) do
System.put_env(@ld_library_path, "#{p}:#{ld_library_path()}")
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, "bin")
crosscompile = Utils.crosscompile(gcc_path, system_path)
System.put_env("PKG_CONFIG", Path.join(toolchain_path, "bin/pkg-config"))
System.put_env("PKG_CONFIG_SYSROOT_DIR", sdk_sysroot)
System.put_env("PKG_CONFIG_LIBDIR", Path.join(sdk_sysroot, "lib/pkgconfig"))
System.put_env("PKG_CONFIG_PATH", "")
System.put_env("PERLLIB", Path.join(toolchain_path, "lib/perl"))
Path.join(toolchain_path, "bin")
|> System.Env.path_add()
Path.join(toolchain_path, "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()
System.put_env("CMAKE_TOOLCHAIN_FILE", Path.expand(Path.join(__DIR__, "nerves-env.cmake")))
{toolchain_path, crosscompile}
end
System.put_env("NERVES_SDK_IMAGES", Path.join(system_path, "images"))
System.put_env("NERVES_SDK_SYSROOT", sdk_sysroot)
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 -O2 --sysroot #{sdk_sysroot}"
)
System.put_env(
"CPPFLAGS",
"-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 --sysroot #{sdk_sysroot}"
)
System.put_env(
"CXXFLAGS",
"-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -pipe -O2 --sysroot #{sdk_sysroot}"
)
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#{erl_interface_dir}/lib -lei")
# pkg-config
System.put_env("PKG_CONFIG_SYSROOT_DIR", sdk_sysroot)
System.put_env("PKG_CONFIG_LIBDIR", "#{sdk_sysroot}/usr/lib/pkgconfig")
# 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 tools
System.put_env("AR_FOR_BUILD", "ar")
System.put_env("AS_FOR_BUILD", "as")
System.put_env("CC_FOR_BUILD", "cc")
System.put_env("GCC_FOR_BUILD", "gcc")
System.put_env("CXX_FOR_BUILD", "g++")
System.put_env("LD_FOR_BUILD", "ld")
System.put_env("CPPFLAGS_FOR_BUILD", "")
System.put_env("CFLAGS_FOR_BUILD", "")
System.put_env("CXXFLAGS_FOR_BUILD", "")
System.put_env("LDFLAGS_FOR_BUILD", "")
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.
The easiest way to resolve this issue is to install the same version of
Erlang/OTP on your host. See the Nerves installation guide for doing this
using the `asdf` version manager.
The Nerves System (nerves_system_*) dependency determines the OTP version
running on the target. It is possible that a recent update to the Nerves
System pulled in a new version of Erlang/OTP. If you are using an official
Nerves System, you can verify this by reviewing the CHANGELOG.md file that
comes with the release. Run 'mix deps' to see the Nerves System version and
go to that system's repository on https://github.com/nerves-project.
If you need to run a particular version of Erlang/OTP on your target, you can
either lock the nerves_system_* dependency in your mix.exs to an older
version. Note that this route prevents you from receiving security updates
from the official systems. The other option is to build a custom Nerves
system. See the Nerves documentation for building a custom system and then
run 'make menuconfig' and look for the Erlang options.
""")
end