147
147
alr exec alr -- action -r post-fetch # Configure XmlAda, etc
148
148
}
149
149
150
- # A temporary file for langkit setevn
151
- SETENV =$PWD /subprojects/libadalang/setenv.sh
150
+ # A temporary file for langkit environment
151
+ LANGKIT_SETENV =$PWD /subprojects/libadalang/setenv.sh
152
152
153
153
# Build langkit which is required to generate libadalang.
154
154
function build_langkit_raw() {
@@ -160,33 +160,87 @@ function build_langkit_raw() {
160
160
161
161
sed -i.bak -e ' s/GPR_BUILD/GPR_LIBRARY_TYPE/' ./langkit/libmanage.py
162
162
pip install .
163
+
164
+ # On macOS, the full path of gnat.adc is stored in ALI files with case
165
+ # normalization. Upon re-runs, gprbuild is unable to match the
166
+ # normalized path with a non-case-normalized real path. This causes
167
+ # unnecessary recompilations at every run.
168
+ #
169
+ # To avoid that, we use the -gnateb flag which tells GNAT to not use
170
+ # an absolute path for gnat.adc
163
171
python manage.py make --no-mypy --generate-auto-dll-dirs \
164
- --library-types=relocatable --gargs " -cargs -fPIC"
172
+ --library-types=relocatable --gargs " -m -v -cargs:ada -gnateb"
173
+
174
+ if [[ $NODE_ARCH_PLATFORM = * darwin* ]]; then
175
+ find . -name ' *.dylib' -print0 |
176
+ while IFS= read -r -d ' ' lib; do
177
+ fix_dylib_rpaths " $lib "
178
+ done
179
+ fi
165
180
166
- # Export the environment to use langkit into a file for later usage
167
- python manage.py setenv > " $SETENV "
181
+ # Export the environment needed to use langkit into a file for later
182
+ # usage
183
+ python manage.py setenv > " $LANGKIT_SETENV "
168
184
169
185
if [[ $NODE_ARCH_PLATFORM == " x64/win32" ]]; then
170
186
# Fix setenv.sh to be bash script for MSYS2 by replacing
171
187
# 1) C:\ -> /C/ 2) '\' -> '/' and ';' -> ':' 3) ": export" -> "; export"
172
- sed -i -e ' s#\([A-Z]\):\\#/\1/#g' -e ' y#\\;#/:#' -e ' s/: export /; export /' " $SETENV "
173
- cat " $SETENV "
188
+ sed -i -e ' s#\([A-Z]\):\\#/\1/#g' -e ' y#\\;#/:#' -e ' s/: export /; export /' " $LANGKIT_SETENV "
174
189
fi
175
190
176
- # Clean `.ali` and `.o` to avoid static vis relocatable mess
177
- find . -name ' *.o' -delete
178
- find . -name ' *.ali' -delete
191
+ cat " $LANGKIT_SETENV "
179
192
)
180
193
}
181
194
195
+ # On macOS, there are two issues with gprbuild:
196
+ #
197
+ # 1. The linker arguments for rpath produce a leading space into paths:
198
+ # "-Wl,-rpath, @executable_path/...". This makes the dynamic library loader
199
+ # unable to use those rpaths at runtime.
200
+ # 2. The linker uses "@executable_path" which applies in the context of an
201
+ # exectuable but not in a context where the library is loaded directly, which
202
+ # is precisely the case we want when we do `import liblktlang` in Python.
203
+ # Instead, "@loader_path" should be used.
204
+ #
205
+ # This function applies a workaround by removing the leading space from rpath
206
+ # entries, and replacing @executable_path with @loader_path.
207
+ function fix_dylib_rpaths() {
208
+ lib=$1
209
+ # Log the full output of otool for debugging
210
+ otool -l " $lib "
211
+
212
+ # First fix paths with a leading space
213
+ paths_with_space=$( otool -l " $lib " | grep -A2 LC_RPATH | grep " path " | awk ' { print $2 }' )
214
+ for p in $paths_with_space ; do
215
+ install_name_tool -rpath " $p " " ${p/@ executable_path/@ loader_path} " " $lib "
216
+ done
217
+ # Then replace @executable_path with @loader_path in all paths (there can be
218
+ # ones without a leading space, hence doing 2 passes)
219
+ paths_with_exec_path=$( otool -l " $lib " | grep -A2 LC_RPATH | grep " @executable_path" | awk ' { print $2 }' )
220
+ for p in $paths_with_exec_path ; do
221
+ install_name_tool -rpath " $p " " ${p/@ executable_path/@ loader_path} " " $lib "
222
+ done
223
+ }
224
+
182
225
# Run build_langkit_raw in Alire environment
183
226
function build_langkit() {
184
227
# We use 'alr exec' to benefit from Alire setting up GPR_PROJECT_PATH with
185
228
# all the dependencies.
186
229
alr exec bash -- -x " $0 " build_langkit_raw
187
230
}
188
231
189
- function set_langkit_usage_env() {
232
+ # This function adds the paths of DLLs from GCC installation and the Alire deps
233
+ # in alire/cache/dependencies (i.e. Alire deps that haven't been pinned to
234
+ # local checkouts) to the runtime environement so that they may be loaded in
235
+ # cases where the DLLs we build don't have appropriate RPATH entries.
236
+ #
237
+ # This is necessary on Windows and macOS, so PATH and DYLD_LIBRARY_PATH are
238
+ # used.
239
+ #
240
+ # However, on macOS we're now using fix_dylib_rpaths to correct the RPATH
241
+ # entries, so DYLD_LIBRARY_PATH should no longer be necessary. But we keep it
242
+ # for good measure.
243
+ function add_unpinned_deps_dlls_to_runtime_path() {
190
244
ADALIB=$( alr exec gcc -- -print-libgcc-file-name)
191
245
192
246
if [[ $NODE_ARCH_PLATFORM == " x64/win32" ]]; then
@@ -210,19 +264,24 @@ function set_langkit_usage_env() {
210
264
echo " NEW_PATH=$NEW_PATH "
211
265
export DYLD_LIBRARY_PATH=$NEW_PATH :$DYLD_LIBRARY_PATH
212
266
export PATH=$NEW_PATH " :$PATH "
213
-
214
- source " $SETENV "
215
267
}
216
268
217
269
# Build ALS with alire
218
270
function build_als() {
219
- # Check if langkit is usable
220
- set_langkit_usage_env
221
- python -c ' import liblktlang'
271
+ add_unpinned_deps_dlls_to_runtime_path
272
+
273
+ # Check that we can use langkit successfully
274
+ (
275
+ source " $LANGKIT_SETENV "
276
+ # On Windows it is not enough to source the langkit env and unpinned
277
+ # deps. The libraries of pinned Alire dependencies (not under
278
+ # alire/cache/dependencies) must also be made visible.
279
+ alr exec python -- -c ' import liblktlang; print("Imported liblktlang successfully")'
280
+ )
222
281
223
282
# We use 'alr exec' to benefit from Alire setting up GPR_PROJECT_PATH with
224
283
# all the dependencies.
225
- LIBRARY_TYPE=static STANDALONE=no GPRBUILD_CARGS= " $gprbuild_flag " alr exec make -- " VERSION=$TAG " all
284
+ LIBRARY_TYPE=static STANDALONE=no alr exec make -- " VERSION=$TAG " all
226
285
}
227
286
228
287
function test_als() {
0 commit comments