The unpac monorepo manager self-hosting as a monorepo using unpac
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Allow libdir to be found relative to bindir

When configured with --with-relative-libdir, the runtime uses the
directory of the executable to determine the location of the Standard
Library. Thus, ocamlrun and the compilers look for ../lib/ocaml by
default.

This is implemented by changing caml_standard_library_default to be a
relative path, and then computing the actual value at startup (for
bytecode) and when queried (for native).

Executables (and objects) produced by the compiler always have an
absolute value of caml_standard_library_default. ocamlc.opt and
ocamlopt.opt are built using -set-runtime-default to force
caml_standard_library_default to be a relative value.

+493 -43
+8 -4
Changes
··· 82 82 normalised on both Windows and Unix. 83 83 (David Allsopp, review by Jonah Beckford, Damien Doligez and Hugo Heuzard) 84 84 85 - - #14244: Executables linked with `ocamlc -custom` now always attempt to load 86 - bytecode from the executable itself, rather than first trying `argv[0]`. 87 - (David Allsopp, review by Jonah Beckford, Antonin Décimo, Damien Doligez and 88 - Samuel Hym) 85 + - #14244: Added --with-relative-libdir which allows the runtime and the 86 + compilers to locate the Standard Library relative to where the binaries 87 + themselves are installed, removing the absolute path previously embedded in 88 + caml_standard_library_default. Executables linked with `ocamlc -custom` now 89 + always attempt to load bytecode from the executable itself, rather than first 90 + trying `argv[0]`. 91 + (David Allsopp, review by Jonah Beckford, Antonin Décimo, Damien Doligez, 92 + Samuel Hym and Vincent Laviron) 89 93 90 94 - #12269, #12410, #13063: Fix unsafety, deadlocks, and/or leaks should 91 95 rare errors happen during domain creation and thread
+13 -2
Makefile
··· 899 899 $(FLEXDLL_SOURCES) | $(BYTE_BINDIR)/flexlink$(EXE) $(OPT_BINDIR) 900 900 rm -f $(FLEXDLL_SOURCE_DIR)/flexlink.exe 901 901 $(MAKE) -C $(FLEXDLL_SOURCE_DIR) $(FLEXLINK_BUILD_ENV) \ 902 - OCAMLOPT='$(FLEXLINK_OCAMLOPT) -nostdlib -I ../stdlib' flexlink.exe 902 + OCAMLOPT='$(FLEXLINK_OCAMLOPT) $(USE_STDLIB) $(SET_RELATIVE_STDLIB)' \ 903 + flexlink.exe 903 904 cp $(FLEXDLL_SOURCE_DIR)/flexlink.exe $@ 904 905 rm -f $(OPT_BINDIR)/flexlink$(EXE) 905 906 cd $(OPT_BINDIR); $(LN) $(call ROOT_FROM, $(OPT_BINDIR))/$@ flexlink$(EXE) ··· 1408 1409 1409 1410 C_LITERAL = $(shell $(SAK) $(ENCODE_C_LITERAL) '$(1)') 1410 1411 1411 - runtime/build_config.h: $(ROOTDIR)/Makefile.config $(SAK) 1412 + runtime/build_config.h: $(ROOTDIR)/Makefile.config \ 1413 + $(ROOTDIR)/Makefile.build_config $(SAK) 1412 1414 $(V_GEN){ \ 1413 1415 echo '/* This file is generated from $(ROOTDIR)/Makefile.config */'; \ 1414 1416 printf '#define OCAML_STDLIB_DIR %s\n' \ ··· 2026 2028 testsuite/tools/test_in_prefi%: CAMLC = $(BEST_OCAMLC) $(STDLIBFLAGS) 2027 2029 2028 2030 test_in_prefix_BYTECODE_LINKFLAGS += -custom 2031 + 2032 + ifeq "$(TARGET_LIBDIR_IS_RELATIVE)" "true" 2033 + # testsuite/tools/test_in_prefix cannot use a relative stdlib because it is run 2034 + # from testsuite/tools, not from the installation tree (the alternative would be 2035 + # to compile it directly with the installed compiler) 2036 + test_in_prefix_NATIVE_LINKFLAGS = 2037 + test_in_prefix_COMMON_LINKFLAGS = \ 2038 + -set-runtime-default 'standard_library_default=$(LIBDIR)' 2039 + endif 2029 2040 2030 2041 testsuite/tools/test_in_prefi%: CAMLOPT = $(BEST_OCAMLOPT) $(STDLIBFLAGS) 2031 2042
+1
Makefile.build_config.in
··· 143 143 144 144 ### Where to look for the standard library on target 145 145 TARGET_LIBDIR=@TARGET_LIBDIR@ 146 + TARGET_LIBDIR_IS_RELATIVE=@target_libdir_is_relative@ 146 147 147 148 unix_directory = @unix_directory@ 148 149 unix_library = @unix_library@
+9 -3
Makefile.common
··· 38 38 CONVERT_PATH = $(strip $(1)) 39 39 endif 40 40 41 + QUOTE_SINGLE = '$(subst ','\'',$(1))' 42 + 41 43 V ?= 0 42 44 43 45 ifeq "$(V)" "0" ··· 176 178 OPTCOMPFLAGS += -function-sections 177 179 endif 178 180 179 - # Allow Makefile.cross to add flags to OC_COMMON_LINKFLAGS 180 - OC_CROSS_LINKFLAGS ?= 181 - OC_COMMON_LINKFLAGS += $(OC_CROSS_LINKFLAGS) 181 + # Allow Makefile.cross to override the Standard Library default for the compiler 182 + # itself. 183 + HOST_LIBDIR ?= $(TARGET_LIBDIR) 184 + 185 + OC_COMMON_LINKFLAGS += \ 186 + -set-runtime-default \ 187 + $(call QUOTE_SINGLE,standard_library_default=$(HOST_LIBDIR)) 182 188 183 189 # The rule to compile C files 184 190
+1 -1
Makefile.cross
··· 48 48 # cross/lib/ocaml for Config.standard_library_default 49 49 CROSS_COMPILER_OVERRIDES=$(CROSS_OVERRIDES) CAMLC=ocamlc CAMLOPT=ocamlopt \ 50 50 BEST_OCAMLC=ocamlc BEST_OCAMLOPT=ocamlopt BEST_OCAMLLEX=ocamllex \ 51 - "OC_CROSS_LINKFLAGS=-set-runtime-default 'standard_library_default=$(LIBDIR)'" 51 + HOST_LIBDIR="$(LIBDIR)" 52 52 CROSS_COMPILERLIBS_OVERRIDES=$(CROSS_OVERRIDES) CAMLC=ocamlc \ 53 53 CAMLOPT="$(ROOTDIR)/ocamlopt.opt$(EXE) $(STDLIBFLAGS)" 54 54
+98 -5
configure
··· 800 800 build_vendor 801 801 build_cpu 802 802 build 803 + target_libdir_is_relative 803 804 ar_supports_response_files 804 805 QS 805 806 TARGET_LIBDIR ··· 1045 1046 enable_flat_float_array 1046 1047 enable_function_sections 1047 1048 enable_mmap_map_stack 1049 + with_relative_libdir 1048 1050 with_afl 1049 1051 with_flexdll 1050 1052 with_winpthreads_msvc ··· 1775 1777 --with-additional-stublibsdir 1776 1778 additional directory for searching for bytecode stub 1777 1779 libraries 1780 + --with-relative-libdir location of the Standard Library, specified relative 1781 + to --bindir (if no argument is given to 1782 + --with-relative-libdir, defaults to ../lib/ocaml) 1778 1783 --with-afl use the AFL fuzzer 1779 1784 --with-flexdll bootstrap FlexDLL from the given sources 1780 1785 --with-winpthreads-msvc build winpthreads (only for the MSVC port) from the ··· 3372 3377 unix_library="" 3373 3378 unix_directory="" 3374 3379 diff_supports_color=false 3380 + target_libdir_is_relative=false 3375 3381 3376 3382 # Information about the package 3377 3383 ··· 3579 3585 3580 3586 3581 3587 3588 + 3582 3589 ## Generated files 3583 3590 3584 3591 ac_config_files="$ac_config_files Makefile.build_config" ··· 4353 4360 if test ${enable_mmap_map_stack+y} 4354 4361 then : 4355 4362 enableval=$enable_mmap_map_stack; 4363 + fi 4364 + 4365 + 4366 + 4367 + # Check whether --with-relative-libdir was given. 4368 + if test ${with_relative_libdir+y} 4369 + then : 4370 + withval=$with_relative_libdir; case $withval in #( 4371 + no) : 4372 + bindir_to_libdir='' ;; #( 4373 + yes) : 4374 + bindir_to_libdir="..${default_separator}lib${default_separator}ocaml" ;; #( 4375 + *) : 4376 + bindir_to_libdir="$withval" ;; 4377 + esac 4378 + else $as_nop 4379 + bindir_to_libdir='' 4356 4380 fi 4357 4381 4358 4382 ··· 17792 17816 17793 17817 # Checks for header files 17794 17818 17819 + ac_fn_c_check_header_compile "$LINENO" "libgen.h" "ac_cv_header_libgen_h" "$ac_includes_default" 17820 + if test "x$ac_cv_header_libgen_h" = xyes 17821 + then : 17822 + printf "%s\n" "#define HAS_LIBGEN_H 1" >>confdefs.h 17823 + 17824 + fi 17825 + 17795 17826 ac_fn_c_check_header_compile "$LINENO" "pthread_np.h" "ac_cv_header_pthread_np_h" "$ac_includes_default" 17796 17827 if test "x$ac_cv_header_pthread_np_h" = xyes 17797 17828 then : ··· 24262 24293 ;; 24263 24294 esac 24264 24295 24296 + if test x"$libdir" = x'${exec_prefix}/lib/ocaml' 24297 + then : 24298 + if test x"$bindir_to_libdir" != 'x' 24299 + then : 24300 + ocaml_libdir="$bindir_to_libdir" 24301 + target_libdir_is_relative=true 24302 + case $cygwin_build_env,$host in #( 24303 + true,*-w64-mingw32*|true,*-pc-windows) : 24304 + build_bindir_to_libdir="$(LC_ALL=C.UTF-8 cygpath \ 24305 + "$bindir_to_libdir")" ;; #( 24306 + *) : 24307 + build_bindir_to_libdir="$bindir_to_libdir" ;; 24308 + esac 24309 + case $build_bindir_to_libdir in #( 24310 + ./*) : 24311 + libdir="$bindir${build_bindir_to_libdir#.}" ;; #( 24312 + ../*) : 24313 + libdir="$bindir/$build_bindir_to_libdir" ;; #( 24314 + *) : 24315 + as_fn_error $? "--with-relative-libdir requires an explicit relative path" "$LINENO" 5 ;; 24316 + esac 24317 + fi 24318 + else $as_nop 24319 + if test x"$bindir_to_libdir" != 'x' 24320 + then : 24321 + as_fn_error $? "--with-relative-libdir and --libdir cannot both be specified" "$LINENO" 5 24322 + fi 24323 + fi 24324 + 24325 + if test x"$bindir_to_libdir" != 'x' && test x"$TARGET_LIBDIR" != 'x' 24326 + then : 24327 + as_fn_error $? "--with-relative-libdir and TARGET_LIBDIR cannot both be specified" "$LINENO" 5 24328 + fi 24329 + 24265 24330 # Define a few macros that were defined in config/m-nt.h 24266 24331 # but whose value is not guessed properly by configure 24267 24332 # (all this should be understood and fixed) ··· 24454 24519 exec_prefix="$prefix" 24455 24520 fi 24456 24521 eval "exec_prefix=\"$exec_prefix\"" 24457 - eval "ocaml_bindir=\"$ocaml_bindir\"" 24458 - eval "ocaml_libdir=\"$ocaml_libdir\"" 24522 + # Set variables necessary to create utils/config.generated.ml and the two 24523 + # runtime-launch-info templates in stdlib. 24524 + # $ocaml_bindir is used for utils/config.generated.ml and is _empty_ if the 24525 + # compiler is configured with --with-relative-libdir (otherwise the path 24526 + # would be embedded in config.cmo) 24527 + # $HOST_BINDIR and $TARGET_BINDIR are used to generate the two 24528 + # runtime-launch-info files. $HOST_BINDIR is always the absolute path to the 24529 + # binary directory, in host format (i.e. potentially with backslashes on 24530 + # Windows). $TARGET_BINDIR can be specified by the caller when building 24531 + # cross-compilers, and the value then is used unaltered. Otherwise, 24532 + # $TARGET_BINDIR is set to '.' when the compiler is configured with 24533 + # --with-relative-libdir or the value of $HOST_BINDIR otherwise. 24534 + eval "HOST_BINDIR=\"$ocaml_bindir\"" 24535 + if test "x$bindir_to_libdir" = 'x' 24536 + then : 24537 + ocaml_bindir="$HOST_BINDIR" 24538 + else $as_nop 24539 + ocaml_bindir='' 24540 + fi 24459 24541 if test x"$TARGET_BINDIR" = 'x' 24460 24542 then : 24461 - TARGET_BINDIR="$ocaml_bindir" 24543 + if test "x$bindir_to_libdir" = 'x' 24544 + then : 24545 + TARGET_BINDIR="$HOST_BINDIR" 24546 + else $as_nop 24547 + TARGET_BINDIR='.' 24548 + fi 24462 24549 fi 24550 + eval "ocaml_libdir=\"$ocaml_libdir\"" 24463 24551 if test x"$TARGET_LIBDIR" = 'x' 24464 24552 then : 24553 + if test "x$bindir_to_libdir" = 'x' 24554 + then : 24465 24555 TARGET_LIBDIR="$ocaml_libdir" 24556 + else $as_nop 24557 + TARGET_LIBDIR="$bindir_to_libdir" 24558 + fi 24466 24559 fi 24467 24560 if test x"$target_launch_method" = 'x' 24468 24561 then : ··· 25426 25519 launch_method='$(echo "$launch_method" | sed -e "s/'/'\"'\"'/g")' 25427 25520 target_launch_method=\ 25428 25521 '$(echo "$target_launch_method" | sed -e "s/'/'\"'\"'/g")' 25429 - ocaml_bindir='$(echo "$ocaml_bindir" | sed -e "s/'/'\"'\"'/g")' 25522 + HOST_BINDIR='$(echo "$HOST_BINDIR" | sed -e "s/'/'\"'\"'/g")' 25430 25523 TARGET_BINDIR='$(echo "$TARGET_BINDIR" | sed -e "s/'/'\"'\"'/g")' 25431 25524 25432 25525 ocamltest_unix_mod='$ocamltest_unix_mod' ··· 26612 26705 chmod +x "$ofile" 26613 26706 26614 26707 ;; 26615 - "shebang":C) printf '%s\n%s\000\n' "$launch_method" "$ocaml_bindir" \ 26708 + "shebang":C) printf '%s\n%s\000\n' "$launch_method" "$HOST_BINDIR" \ 26616 26709 > stdlib/runtime.info 26617 26710 printf '%s\n%s\000\n' "$target_launch_method" "$TARGET_BINDIR" \ 26618 26711 > stdlib/target_runtime.info ;;
+64 -5
configure.ac
··· 84 84 unix_library="" 85 85 unix_directory="" 86 86 diff_supports_color=false 87 + target_libdir_is_relative=false 87 88 88 89 # Information about the package 89 90 ··· 268 269 AC_SUBST([TARGET_LIBDIR]) 269 270 AC_SUBST([QS]) 270 271 AC_SUBST([ar_supports_response_files]) 272 + AC_SUBST([target_libdir_is_relative]) 271 273 272 274 ## Generated files 273 275 ··· 681 683 [AS_HELP_STRING([--enable-mmap-map-stack], 682 684 [use mmap to allocate stacks instead of malloc])]) 683 685 686 + AC_ARG_WITH([relative-libdir], 687 + [AS_HELP_STRING([--with-relative-libdir], 688 + m4_normalize([location of the Standard Library, specified relative to 689 + --bindir (if no argument is given to --with-relative-libdir, defaults to 690 + ../lib/ocaml)]))], 691 + [AS_CASE([$withval], 692 + [no], 693 + [bindir_to_libdir=''], 694 + [yes], 695 + [bindir_to_libdir="..${default_separator}lib${default_separator}ocaml"], 696 + [bindir_to_libdir="$withval"])], 697 + [bindir_to_libdir='']) 698 + 684 699 AC_ARG_WITH([afl], 685 700 [AS_HELP_STRING([--with-afl], 686 701 [use the AFL fuzzer])]) ··· 957 972 # in config.status, rather than by the .in mechanism, since the latter cannot 958 973 # reliably process binary files. 959 974 AC_CONFIG_COMMANDS([shebang], 960 - [printf '%s\n%s\000\n' "$launch_method" "$ocaml_bindir" \ 975 + [printf '%s\n%s\000\n' "$launch_method" "$HOST_BINDIR" \ 961 976 > stdlib/runtime.info 962 977 printf '%s\n%s\000\n' "$target_launch_method" "$TARGET_BINDIR" \ 963 978 > stdlib/target_runtime.info], ··· 968 983 [launch_method='$(echo "$launch_method" | sed -e "s/'/'\"'\"'/g")' 969 984 target_launch_method=\ 970 985 '$(echo "$target_launch_method" | sed -e "s/'/'\"'\"'/g")' 971 - ocaml_bindir='$(echo "$ocaml_bindir" | sed -e "s/'/'\"'\"'/g")' 986 + HOST_BINDIR='$(echo "$HOST_BINDIR" | sed -e "s/'/'\"'\"'/g")' 972 987 TARGET_BINDIR='$(echo "$TARGET_BINDIR" | sed -e "s/'/'\"'\"'/g")']) 973 988 974 989 # Checks for programs ··· 1351 1366 1352 1367 # Checks for header files 1353 1368 1369 + AC_CHECK_HEADER([libgen.h],[AC_DEFINE([HAS_LIBGEN_H], [1])]) 1354 1370 AC_CHECK_HEADER([pthread_np.h],[AC_DEFINE([HAS_PTHREAD_NP_H], [1])]) 1355 1371 AC_CHECK_HEADER([dirent.h], [AC_DEFINE([HAS_DIRENT], [1])], [], 1356 1372 [#include <sys/types.h>]) ··· 3000 3016 [ocaml_libdir='${exec_prefix}\lib\ocaml'], 3001 3017 [ocaml_libdir="$libdir"])])]) 3002 3018 3019 + AS_IF([test x"$libdir" = x'${exec_prefix}/lib/ocaml'], 3020 + [AS_IF([test x"$bindir_to_libdir" != 'x'], 3021 + [ocaml_libdir="$bindir_to_libdir" 3022 + target_libdir_is_relative=true 3023 + AS_CASE([$cygwin_build_env,$host], 3024 + [true,*-w64-mingw32*|true,*-pc-windows], 3025 + [build_bindir_to_libdir="$(LC_ALL=C.UTF-8 cygpath \ 3026 + "$bindir_to_libdir")"], 3027 + [build_bindir_to_libdir="$bindir_to_libdir"]) 3028 + AS_CASE([$build_bindir_to_libdir], 3029 + [./*],[libdir="$bindir${build_bindir_to_libdir[#].}"], 3030 + [../*],[libdir="$bindir/$build_bindir_to_libdir"], 3031 + [AC_MSG_ERROR(m4_normalize([--with-relative-libdir requires an explicit 3032 + relative path]))])])], 3033 + [AS_IF([test x"$bindir_to_libdir" != 'x'], 3034 + [AC_MSG_ERROR(m4_normalize([--with-relative-libdir and --libdir cannot both 3035 + be specified]))])]) 3036 + 3037 + AS_IF([test x"$bindir_to_libdir" != 'x' && test x"$TARGET_LIBDIR" != 'x'], 3038 + [AC_MSG_ERROR(m4_normalize([--with-relative-libdir and TARGET_LIBDIR cannot 3039 + both be specified]))]) 3040 + 3003 3041 # Define a few macros that were defined in config/m-nt.h 3004 3042 # but whose value is not guessed properly by configure 3005 3043 # (all this should be understood and fixed) ··· 3029 3067 AS_IF([test "x$prefix" = "xNONE"],[prefix="$ac_default_prefix"]) 3030 3068 AS_IF([test "x$exec_prefix" = "xNONE"],[exec_prefix="$prefix"]) 3031 3069 eval "exec_prefix=\"$exec_prefix\"" 3032 - eval "ocaml_bindir=\"$ocaml_bindir\"" 3070 + # Set variables necessary to create utils/config.generated.ml and the two 3071 + # runtime-launch-info templates in stdlib. 3072 + # $ocaml_bindir is used for utils/config.generated.ml and is _empty_ if the 3073 + # compiler is configured with --with-relative-libdir (otherwise the path 3074 + # would be embedded in config.cmo) 3075 + # $HOST_BINDIR and $TARGET_BINDIR are used to generate the two 3076 + # runtime-launch-info files. $HOST_BINDIR is always the absolute path to the 3077 + # binary directory, in host format (i.e. potentially with backslashes on 3078 + # Windows). $TARGET_BINDIR can be specified by the caller when building 3079 + # cross-compilers, and the value then is used unaltered. Otherwise, 3080 + # $TARGET_BINDIR is set to '.' when the compiler is configured with 3081 + # --with-relative-libdir or the value of $HOST_BINDIR otherwise. 3082 + eval "HOST_BINDIR=\"$ocaml_bindir\"" 3083 + AS_IF([test "x$bindir_to_libdir" = 'x'], 3084 + [ocaml_bindir="$HOST_BINDIR"], 3085 + [ocaml_bindir='']) 3086 + AS_IF([test x"$TARGET_BINDIR" = 'x'], 3087 + [AS_IF([test "x$bindir_to_libdir" = 'x'], 3088 + [TARGET_BINDIR="$HOST_BINDIR"], 3089 + [TARGET_BINDIR='.'])]) 3033 3090 eval "ocaml_libdir=\"$ocaml_libdir\"" 3034 - AS_IF([test x"$TARGET_BINDIR" = 'x'],[TARGET_BINDIR="$ocaml_bindir"]) 3035 - AS_IF([test x"$TARGET_LIBDIR" = 'x'],[TARGET_LIBDIR="$ocaml_libdir"]) 3091 + AS_IF([test x"$TARGET_LIBDIR" = 'x'], 3092 + [AS_IF([test "x$bindir_to_libdir" = 'x'], 3093 + [TARGET_LIBDIR="$ocaml_libdir"], 3094 + [TARGET_LIBDIR="$bindir_to_libdir"])]) 3036 3095 AS_IF([test x"$target_launch_method" = 'x'], 3037 3096 [target_launch_method="$launch_method"]) 3038 3097 prefix="$saved_prefix"
+10 -1
ocamltest/ocaml_tests.ml
··· 46 46 check_program_output; 47 47 ] @ 48 48 (if not Sys.win32 && Ocamltest_config.native_compiler then 49 - opt_build @ [compare_bytecode_programs] 49 + (* If the compiler is configured using --with-relative-libdir then at 50 + present we can't compare the bytecode programs because ocamlc.opt and 51 + ocamlrun are at different levels in the build tree, but they're both 52 + configured with the same relative directory path. 53 + This problem will disappear when ocamltest runs the testsuite against a 54 + compiler in an install-tree like way. *) 55 + if Ocamltest_config.has_relative_libdir then 56 + opt_build 57 + else 58 + opt_build @ [compare_bytecode_programs] 50 59 else 51 60 [] 52 61 )
+2
ocamltest/ocamltest_config.ml.in
··· 102 102 let frame_pointers = @frame_pointers@ 103 103 104 104 let tsan = @tsan@ 105 + 106 + let has_relative_libdir = @target_libdir_is_relative@
+3
ocamltest/ocamltest_config.mli
··· 145 145 146 146 val tsan : bool 147 147 (** Whether ThreadSanitizer support has been enabled at configure time *) 148 + 149 + val has_relative_libdir : bool 150 + (** Whether the compiler has been configured using --with-relative-libdir *)
+28
runtime/caml/osdeps.h
··· 96 96 void caml_plat_mem_decommit(void *, uintnat); 97 97 void caml_plat_mem_unmap(void *, uintnat); 98 98 99 + /* caml_locate_standard_library(exe_name, stdlib_default, dirname) returns the 100 + location of the Standard Library. The location returned is absolute, if 101 + stdlib_default is a relative path then the result is computed relative to the 102 + directory portion of exe_name. 103 + 104 + If dirname is not NULL and stdlib_default is a relative path, a copy of the 105 + directory name part of exe_name is returned in dirname. If stdlib_default is 106 + an absolute path, dirname is never changed. 107 + 108 + Both strings are allocated with [caml_stat_alloc], so should be freed using 109 + [caml_stat_free]. 110 + */ 111 + CAMLextern char_os *caml_locate_standard_library (const char_os *exe_name, 112 + const char_os *stdlib_default, 113 + char_os **dirname); 114 + 99 115 #ifdef _WIN32 100 116 101 117 #include <time.h> ··· 158 174 CAMLextern uint64_t caml_time_counter(void); 159 175 160 176 extern void caml_init_os_params(void); 177 + 178 + /* True if: 179 + - dir equals "." 180 + - dir equals ".." 181 + - dir begins "./" 182 + - dir begins "../" 183 + The tests for null avoid the need to call strlen_os. */ 184 + #define Is_relative_dir(dir) \ 185 + (dir[0] == '.' \ 186 + && (dir[1] == '\0' \ 187 + || Is_separator(dir[1]) \ 188 + || (dir[1] == '.' && (dir[2] == '\0' || Is_separator(dir[2]))))) 161 189 162 190 #endif /* CAML_INTERNALS */ 163 191
+4
runtime/caml/s.h.in
··· 116 116 117 117 #undef HAS_DECL_SETTHREADDESCRIPTION 118 118 119 + #undef HAS_LIBGEN_H 120 + 121 + /* Define HAS_LIBGEN_H if you have /usr/include/libgen.h. */ 122 + 119 123 #undef HAS_DIRENT 120 124 121 125 /* Define HAS_DIRENT if you have /usr/include/dirent.h and the result of
+1
runtime/caml/startup.h
··· 59 59 /* The default location of the Standard Library as used by the runtime to find 60 60 ld.conf */ 61 61 extern const char_os *caml_runtime_standard_library_default; 62 + extern const char_os *caml_runtime_standard_library_effective; 62 63 63 64 #endif /* CAML_INTERNALS */ 64 65
+1 -1
runtime/dynlink.c
··· 278 278 if (lib_path != NULL) 279 279 for (char_os *p = lib_path; *p != 0; p += strlen_os(p) + 1) 280 280 caml_ext_table_add(&caml_shared_libs_path, p); 281 - caml_parse_ld_conf(caml_runtime_standard_library_default, 281 + caml_parse_ld_conf(caml_runtime_standard_library_effective, 282 282 &caml_shared_libs_path); 283 283 /* Open the shared libraries */ 284 284 caml_ext_table_init(&shared_libs, 8);
+36 -14
runtime/startup_byt.c
··· 72 72 #define SEEK_END 2 73 73 #endif 74 74 75 + const char_os * caml_runtime_standard_library_effective = NULL; 76 + 75 77 static char magicstr[EXEC_MAGIC_LENGTH+1]; 76 78 77 79 /* Print the specified error message followed by an end-of-line and exit */ ··· 379 381 const char_os * stdlib; 380 382 stdlib = caml_secure_getenv(T("OCAMLLIB")); 381 383 if (stdlib == NULL) stdlib = caml_secure_getenv(T("CAMLLIB")); 382 - if (stdlib == NULL) stdlib = caml_runtime_standard_library_default; 384 + if (stdlib == NULL) stdlib = caml_runtime_standard_library_effective; 383 385 return stdlib; 384 386 } 385 387 ··· 431 433 puts("shared_libs_path:"); 432 434 caml_decompose_path(&caml_shared_libs_path, 433 435 caml_secure_getenv(T("CAML_LD_LIBRARY_PATH"))); 434 - caml_parse_ld_conf(caml_runtime_standard_library_default, 436 + caml_parse_ld_conf(caml_runtime_standard_library_effective, 435 437 &caml_shared_libs_path); 436 438 for (int i = 0; i < caml_shared_libs_path.size; i++) { 437 439 dir = caml_shared_libs_path.contents[i]; ··· 467 469 value res; 468 470 char * req_prims; 469 471 char_os * shared_lib_path, * shared_libs; 470 - char_os * exe_name, * proc_self_exe; 472 + char_os * exe_name, * proc_self_exe, * argv0; 471 473 472 474 /* Determine options */ 473 475 caml_parse_ocamlrunparam(); ··· 488 490 /* Determine position of bytecode file */ 489 491 pos = 0; 490 492 491 - proc_self_exe = caml_executable_name(); 493 + argv0 = proc_self_exe = caml_executable_name(); 492 494 493 495 /* In APPENDED mode (i.e. with -custom), we always want to load the bytecode 494 496 from the running executable, and argv[0] should never be used. However, ··· 519 521 error("unable to open file '%s'", caml_stat_strdup_of_os(exe_name)); 520 522 } 521 523 524 + if (argv0 == NULL) 525 + argv0 = caml_search_exe_in_path(exe_name); 526 + 522 527 if (fd < 0) { 523 528 pos = parse_command_line(argv); 524 529 if (caml_params->print_config) { 530 + caml_runtime_standard_library_effective = 531 + caml_locate_standard_library(argv0, 532 + caml_runtime_standard_library_default, 533 + NULL); 534 + 525 535 do_print_config(); 526 536 exit(0); 527 537 } ··· 552 562 } 553 563 /* Read the table of contents (section descriptors) */ 554 564 caml_read_section_descriptors(fd, &trail); 565 + 566 + caml_runtime_standard_library_effective = 567 + caml_locate_standard_library(argv0, 568 + caml_runtime_standard_library_default, NULL); 569 + if (argv0 != proc_self_exe) 570 + caml_stat_free(argv0); 571 + 572 + /* Load the embedded overridden caml_standard_library_default value, if one is 573 + available. Note that although -custom executables come through this 574 + mechanism, they don't define OSLD sections because 575 + caml_runtime_standard_library_default and caml_standard_library_default are 576 + fundamentally equal and caml_runtime_standard_library_default is set when 577 + the -custom executable is linked. */ 578 + char_os *image_standard_library_default = 579 + read_section_to_os(fd, &trail, "OSLD"); 580 + if (image_standard_library_default != NULL) 581 + caml_standard_library_default = image_standard_library_default; 582 + 555 583 /* Initialize the abstract machine */ 556 584 caml_init_gc (); 557 585 ··· 575 603 req_prims = read_section(fd, &trail, "PRIM"); 576 604 if (req_prims == NULL) caml_fatal_error("no PRIM section"); 577 605 caml_build_primitive_table(shared_lib_path, shared_libs, req_prims); 578 - /* Load the embedded overridden caml_standard_library_default value, if one is 579 - available. Note that although -custom executables come through this 580 - mechanism, they don't define OSLD sections because 581 - caml_runtime_standard_library_default and caml_standard_library_default are 582 - fundamentally equal and caml_runtime_standard_library_default is set when 583 - the -custom executable is linked. */ 584 - char_os *image_standard_library_default = 585 - read_section_to_os(fd, &trail, "OSLD"); 586 - if (image_standard_library_default != NULL) 587 - caml_standard_library_default = image_standard_library_default; 588 606 caml_stat_free(shared_lib_path); 589 607 caml_stat_free(shared_libs); 590 608 caml_stat_free(req_prims); ··· 662 680 exe_name = caml_search_exe_in_path(argv[0]); 663 681 else 664 682 exe_name = proc_self_exe; 683 + 684 + caml_runtime_standard_library_effective = 685 + caml_locate_standard_library(exe_name, 686 + caml_runtime_standard_library_default, NULL); 665 687 666 688 Caml_state->external_raise = NULL; 667 689 /* Setup signal handling */
+23
runtime/sys.c
··· 754 754 } 755 755 #endif 756 756 757 + CAMLprim value caml_sys_get_stdlib_dirs(value vstdlib_default) 758 + { 759 + CAMLparam1(vstdlib_default); 760 + CAMLlocal3(result, eff, root_dir); 761 + 762 + char_os *stdlib_default = caml_stat_strdup_to_os(String_val(vstdlib_default)); 763 + char_os *root = NULL, *stdlib; 764 + 765 + stdlib = 766 + caml_locate_standard_library(caml_params->exe_name, stdlib_default, &root); 767 + 768 + eff = caml_copy_string_of_os(stdlib); 769 + if (root == NULL) { 770 + root_dir = Val_none; 771 + } else { 772 + root_dir = caml_copy_string_of_os(root); 773 + root_dir = caml_alloc_some(root_dir); 774 + } 775 + result = caml_alloc_2(0, eff, root_dir); 776 + 777 + CAMLreturn(result); 778 + } 779 + 757 780 CAMLprim value caml_sys_get_config(value unit) 758 781 { 759 782 CAMLparam0 (); /* unit is unused */
+70
runtime/unix.c
··· 54 54 #else 55 55 #include <sys/dir.h> 56 56 #endif 57 + #ifdef HAS_LIBGEN_H 58 + #include <libgen.h> 59 + #endif 57 60 #ifdef __APPLE__ 58 61 #include <mach-o/dyld.h> 59 62 #endif ··· 542 545 if (munmap(mem, size) != 0) 543 546 CAMLassert(0); 544 547 } 548 + 549 + static char * caml_dirname (const char * path) 550 + { 551 + #ifdef HAS_LIBGEN_H 552 + char *dir, *res; 553 + dir = caml_stat_strdup(path); 554 + res = caml_stat_strdup(dirname(dir)); 555 + caml_stat_free(dir); 556 + return res; 557 + #else 558 + /* See Filename.generic_dirname */ 559 + ptrdiff_t n = strlen(path) - 1; 560 + char *res; 561 + if (n < 0) /* path is "" */ 562 + return caml_stat_strdup("."); 563 + while (n >= 0 && path[n] == '/') 564 + n--; 565 + if (n < 0) /* path is entirely slashes */ 566 + return caml_stat_strdup("/"); 567 + while (n >= 0 && path[n] != '/') 568 + n--; 569 + if (n < 0) /* path is relative */ 570 + return caml_stat_strdup("."); 571 + while (n >= 0 && path[n] == '/') 572 + n--; 573 + if (n < 0) /* path is a file at root */ 574 + return caml_stat_strdup("/"); 575 + /* n is the _index_ of the last character of the dirname */ 576 + res = caml_stat_alloc(n + 2); 577 + memcpy(res, path, n + 1); 578 + res[n + 1] = 0; 579 + return res; 580 + #endif 581 + } 582 + 583 + CAMLextern char_os* caml_locate_standard_library (const char *exe_name, 584 + const char *stdlib_default, 585 + char **dirname) 586 + { 587 + if (Is_relative_dir(stdlib_default)) { 588 + char * root = caml_dirname(exe_name); 589 + char * candidate = 590 + caml_stat_strconcat(3, root, CAML_DIR_SEP, stdlib_default); 591 + /* In practice, a system which can be configured --with-relative-libdir will 592 + also have realpath. The directory is normalised here for consistency with 593 + the behaviour on Windows, which doesn't have a direct equivalent of 594 + dirname and performs the equivalent of realpath as a side-effect of 595 + determining the root path. */ 596 + #ifdef HAS_REALPATH 597 + char * resolved_candidate = realpath(candidate, NULL); 598 + /* If realpath fails, use the non-normalised path for error messages. */ 599 + if (resolved_candidate != NULL) { 600 + caml_stat_free(candidate); 601 + /* realpath uses malloc */ 602 + candidate = caml_stat_strdup(resolved_candidate); 603 + free(resolved_candidate); 604 + } 605 + #endif 606 + if (dirname == NULL) 607 + caml_stat_free(root); 608 + else 609 + *dirname = root; 610 + return candidate; 611 + } else { 612 + return caml_stat_strdup(stdlib_default); 613 + } 614 + }
+86
runtime/win32.c
··· 41 41 #include <errno.h> 42 42 #include <string.h> 43 43 #include <signal.h> 44 + #include <wchar.h> 44 45 #include "caml/alloc.h" 45 46 #include "caml/codefrag.h" 46 47 #include "caml/fail.h" ··· 1342 1343 caml_win32_sys_error(GetLastError()); 1343 1344 CAMLreturn(caml_copy_string_of_utf16(buf)); 1344 1345 } 1346 + 1347 + CAMLextern char_os* caml_locate_standard_library (const wchar_t *exe_name, 1348 + const wchar_t *stdlib_default, 1349 + wchar_t **dirname) 1350 + { 1351 + if (Is_relative_dir(stdlib_default)) { 1352 + LPWSTR root = NULL, basename; 1353 + DWORD l = MAX_PATH + 1, buf_len; 1354 + 1355 + do { 1356 + buf_len = l; 1357 + caml_stat_free(root); 1358 + root = caml_stat_alloc(buf_len * sizeof(WCHAR)); 1359 + l = GetFullPathName(exe_name, buf_len, root, &basename); 1360 + } while (l >= buf_len); 1361 + /* It should be an Impossible Thing for exe_name (which will have been the 1362 + result of GetModuleFileName) to be unparsable by GetFullPathName */ 1363 + if (l == 0) { 1364 + caml_stat_free(root); 1365 + return caml_stat_wcsdup(stdlib_default); 1366 + } 1367 + 1368 + CAMLassert(basename && basename != root && Is_separator(*(basename - 1))); 1369 + 1370 + /* Make root the dirname portion */ 1371 + *(basename - 1) = 0; 1372 + 1373 + LPWSTR candidate = 1374 + caml_stat_wcsconcat(3, root, CAML_DIR_SEP, stdlib_default); 1375 + HANDLE h = 1376 + CreateFile(candidate, 0, 1377 + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 1378 + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 1379 + if (h == INVALID_HANDLE_VALUE) { 1380 + caml_stat_free(candidate); 1381 + return caml_stat_wcsdup(stdlib_default); 1382 + } 1383 + 1384 + LPWSTR resolved_candidate = NULL; 1385 + l = MAX_PATH + 1; 1386 + do { 1387 + buf_len = l; 1388 + caml_stat_free(resolved_candidate); 1389 + resolved_candidate = caml_stat_alloc(buf_len * sizeof(WCHAR)); 1390 + l = GetFinalPathNameByHandle(h, resolved_candidate, buf_len, 1391 + FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); 1392 + } while (l >= buf_len); 1393 + 1394 + if (l > 0) { 1395 + /* GetFinalPathNameByHandle always returns \\?\ which needs stripping. */ 1396 + CAMLassert(l > 4 && resolved_candidate[0] == '\\' 1397 + && resolved_candidate[1] == '\\' 1398 + && resolved_candidate[2] == '?' 1399 + && resolved_candidate[3] == '\\'); 1400 + 1401 + caml_stat_free(candidate); 1402 + 1403 + if (l >= 8 && resolved_candidate[4] == 'U' 1404 + && resolved_candidate[5] == 'N' 1405 + && resolved_candidate[6] == 'C' 1406 + && resolved_candidate[7] == '\\') { 1407 + /* NT native UNC path (\\?\UNC\foo). We change the last C to a backslash 1408 + (\\?\UN\\foo) and then include that altered character and the 1409 + original final slash to create a normal UNC path. */ 1410 + resolved_candidate[6] = '\\'; 1411 + candidate = caml_stat_wcsdup(resolved_candidate + 6); 1412 + } else { 1413 + /* Local device path */ 1414 + candidate = caml_stat_wcsdup(resolved_candidate + 4); 1415 + } 1416 + } 1417 + 1418 + /* It should be another Impossible Thing for l == 0 in the above. If that 1419 + did happen, candidate will _not_ have been freed, and we'll return the 1420 + path returned by GetFullPathName */ 1421 + caml_stat_free(resolved_candidate); 1422 + 1423 + if (dirname != NULL) 1424 + *dirname = caml_stat_wcsdup(root); 1425 + caml_stat_free(root); 1426 + return candidate; 1427 + } else { 1428 + return caml_stat_wcsdup(stdlib_default); 1429 + } 1430 + }
+1 -3
tools/ocamlmklib.ml
··· 25 25 Printf.sprintf "link -lib -nologo %s-out:%s %s %s" machine out opts files 26 26 else Printf.sprintf "%s rcs %s %s %s" Config.ar out opts files 27 27 28 - (* PR#4783: under Windows, don't use absolute paths because we do 29 - not know where the binary distribution will be installed. *) 30 28 let compiler_path name = 31 - if Sys.os_type = "Win32" then name else Filename.concat Config.bindir name 29 + Filename.concat Config.bindir name 32 30 33 31 let bytecode_objs = ref [] (* .cmo,.cma,.ml,.mli files to pass to ocamlc *) 34 32 and native_objs = ref [] (* .cmx,.ml,.mli files to pass to ocamlopt *)
+19 -1
utils/config.common.ml.in
··· 22 22 23 23 external standard_library_default : unit -> string = "%standard_library_default" 24 24 25 - let standard_library_default = standard_library_default () 25 + let standard_library_default_raw = standard_library_default () 26 + 27 + external stdlib_dirs : string -> string * string option 28 + = "caml_sys_get_stdlib_dirs" 29 + 30 + let standard_library_default, relative_root_dir = 31 + stdlib_dirs standard_library_default_raw 32 + 33 + let standard_library_relative = 34 + if relative_root_dir = None then 35 + None 36 + else 37 + Some standard_library_default_raw 26 38 27 39 let standard_library = 28 40 try ··· 32 44 Sys.getenv "CAMLLIB" 33 45 with Not_found -> 34 46 standard_library_default 47 + 48 + let bindir = Option.value ~default:bindir relative_root_dir 35 49 36 50 let exec_magic_number = {magic|@EXEC_MAGIC_NUMBER@|magic} 37 51 (* exec_magic_number is duplicated in runtime/caml/exec.h *) ··· 80 94 let p x v = (x, String v) in 81 95 let p_int x v = (x, Int v) in 82 96 let p_bool x v = (x, Bool v) in 97 + let standard_library_relative = 98 + Option.value ~default:"" standard_library_relative 99 + in 83 100 [ 84 101 p "version" version; 85 102 p "standard_library_default" standard_library_default; 103 + p "standard_library_relative" standard_library_relative; 86 104 p "standard_library" standard_library; 87 105 p "ccomp_type" ccomp_type; 88 106 p "c_compiler" c_compiler;
+15 -3
utils/config.mli
··· 24 24 (** The current version number of the system *) 25 25 26 26 val bindir: string 27 - (** The directory containing the binary programs *) 27 + (** The directory containing the binary programs. If the compiler was configured 28 + with [--with-relative-libdir] then this will be the directory containing the 29 + currently executing runtime. *) 30 + 31 + val standard_library_relative: string option 32 + (** The explicit relative path from the compiler binaries to the standard 33 + libraries directory if the compiler was configured with 34 + [--with-relative-libdir], or [None] otherwise. 35 + 36 + @since 5.5 *) 28 37 29 38 val standard_library_default: string 30 - (** The configured value for the directory containing the standard libraries 39 + (** The effective value for the default directory containing the standard 40 + libraries. This is always an absolute path, computed using 41 + {!standard_library_relative} if necessary. 31 42 32 43 @since 5.5 *) 33 44 34 45 val standard_library: string 35 - (** The effective directory containing the standard libraries *) 46 + (** The effective directory containing the standard libraries, taking CAMLLIB 47 + and OCAMLLIB into account. *) 36 48 37 49 val ccomp_type: string 38 50 (** The "kind" of the C compiler, assembler and linker used: one of