-
Notifications
You must be signed in to change notification settings - Fork 412
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support installing the compiler to the toolchains directory on windows #11159
Comments
These are my notes for manually building the compiler from source on windows using the x86_64-w64-mingw32 toolchain. The goal is to automate as much of this as necessary within dune, but the first step is being able to manually build the compiler. These instructions are for building the compiler in a way that resembles dune toolchains so we can work on allowing dune to build packages with dune toolchains installed before we figure out how to actually install dune toolchains with dune. These instructions are for bash on windows, such as the bash install that comes with git for windows. Update: patching flexdll is not necessary as long as you don't pass
The toolchain will be installed to Here's the patch for flexdll: flexdll.0.43-winres-remove-prefix.patch And here's a script that does the above. You'll need to modify it with the desired DUNE_TOOLCHAIN_HASH: https://gist.githubusercontent.com/gridbugs/8b402eec445876fb5053c0218f066cbb/raw/366e37a54f50831a6da2f0aa4584228d3ee07aea/install-ocaml-toolchain-windows.sh |
Update on manually building the compiler toolchain on windows: this script from my fork of dune is a simplified version of the instructions in the previous comment and I recommend running that script rather than attempting to follow the instructions above. |
I have a branch on my fork of dune that supports package management on windows: https://github.com/gridbugs/dune/tree/windows-hacks See the differences between that branch and its latest upstream ancestor (bca9e65) for all the problems and workarounds. I'll paste the diff here for convenience. The comments in this patch explain each issue preventing dune pkg from working on windows. Most of the issues are with differences in how paths work between windows and the unixes. diff --git a/src/dune_rules/pkg_toolchain.ml b/src/dune_rules/pkg_toolchain.ml
index db4bd72da..74e7b6ef0 100644
--- a/src/dune_rules/pkg_toolchain.ml
+++ b/src/dune_rules/pkg_toolchain.ml
@@ -39,7 +39,21 @@ let pkg_dir (pkg : Dune_pkg.Lock_dir.Pkg.t) =
Path.Outside_build_dir.relative (base_dir ()) dir_name
;;
-let installation_prefix ~pkg_dir = Path.Outside_build_dir.relative pkg_dir "target"
+let installation_prefix ~pkg_dir =
+ Path.Outside_build_dir.relative pkg_dir "target"
+ (* XXX(steve): replace the backslashes with slashes in the installation
+ prefix. On windows the path will naturally uses backslashes as the path
+ delimiter however this particular path ends up embedded in some generated
+ C code where the backslashes will be treated as escape sequences. Most
+ windows tools are happy with either backslashes or slashes as path
+ delimiters, so replacing them here probably won't cause any problems. It
+ would be better if this logic was built into stdune's [Path] module so we
+ don't need to convert the path to and from a string here. *)
+ |> Path.Outside_build_dir.to_string
+ |> String.split_on_char ~sep:'\\'
+ |> String.concat ~sep:"/"
+ |> Path.Outside_build_dir.of_string
+;;
let is_compiler_and_toolchains_enabled name =
match Config.get Compile_time.toolchains with
@@ -89,25 +103,38 @@ let ocaml context env ~bin_dir =
*)
let installation_prefix_within_tmp_install_dir ~installation_prefix:prefix tmp_install_dir
=
- let target_without_root_prefix =
- (* Remove the root directory prefix from the target directory so
- it can be used to create a path relative to the temporary
- install dir. *)
- match
- String.drop_prefix
- (Path.Outside_build_dir.to_string prefix)
- ~prefix:(Path.External.to_string Path.External.root)
- with
- | Some x -> x
- | None ->
- Code_error.raise
- "Expected prefix to start with root"
- [ "prefix", Path.Outside_build_dir.to_dyn prefix
- ; "root", Path.External.to_dyn Path.External.root
- ; "tmp_install_dir", Path.to_dyn tmp_install_dir
- ]
- in
- Path.relative tmp_install_dir target_without_root_prefix
+ if Sys.win32
+ then
+ (* XXX(steve): it would be better to concatenate the paths here without
+ using the low-level [Filename] module directly. We can't use the
+ higher-level [Path] module here as [Path.relative] treats the directory
+ name C: as a filesystem root. That is normally correct, however in this
+ instance we're trying to refer to a directory literally named "C:" (or
+ possibly a different drive name). *)
+ Path.of_string
+ (Filename.concat
+ (Path.to_string tmp_install_dir)
+ (Path.Outside_build_dir.to_string prefix))
+ else (
+ let target_without_root_prefix =
+ (* Remove the root directory prefix from the target directory so
+ it can be used to create a path relative to the temporary
+ install dir. *)
+ match
+ String.drop_prefix
+ (Path.Outside_build_dir.to_string prefix)
+ ~prefix:(Path.External.to_string Path.External.root)
+ with
+ | Some x -> x
+ | None ->
+ Code_error.raise
+ "Expected prefix to start with root"
+ [ "prefix", Path.Outside_build_dir.to_dyn prefix
+ ; "root", Path.External.to_dyn Path.External.root
+ ; "tmp_install_dir", Path.to_dyn tmp_install_dir
+ ]
+ in
+ Path.relative tmp_install_dir target_without_root_prefix)
;;
let modify_install_action (action : Dune_lang.Action.t) ~installation_prefix ~suffix =
@@ -122,7 +149,11 @@ let modify_install_action (action : Dune_lang.Action.t) ~installation_prefix ~su
Dune_lang.Action.Run
[ Literal make
; Literal install
- ; Slang.text (sprintf "DESTDIR=%s" (Path.to_string tmp_install_dir))
+ (* XXX(steve): the trailing slash in DESTDIR is necessary on windows
+ to prevent the drive name (e.g. "C:") from being concatonated to
+ the temporary directory, rather than made into a subdirectory of
+ it. *)
+ ; Slang.text (sprintf "DESTDIR=%s/" (Path.to_string tmp_install_dir))
]
in
let prefix = Path.outside_build_dir installation_prefix in
@@ -183,6 +214,33 @@ let touch_config_cache =
]
;;
+(* The build commands in the compiler's opam metadata work unmodified with dune
+ toolchains on unixes however on windows this is not the case. This function
+ rewrites the compiler's build action on windows so that it can be
+ installed with dune toolchains. Note that none of these changes are
+ specific to installing with dune toolchains, and are instead required to
+ build the compiler in a non-opam environment. *)
+let rec modify_build_action_windows (action : Dune_lang.Action.t) =
+ match action with
+ | Progn actions ->
+ Dune_lang.Action.Progn (List.map actions ~f:modify_build_action_windows)
+ | Run (Literal prog :: args) ->
+ (match String_with_vars.text_only prog with
+ | Some "./configure" ->
+ (* work around the issue where ./configure doesn't work on windows due to the lack of file extension *)
+ Run
+ (Literal (String_with_vars.make_text Loc.none "bash")
+ :: Literal (String_with_vars.make_text Loc.none "./configure")
+ (* XXX(steve): this is a hack that's specific to the mingw toolchain *)
+ :: Literal (String_with_vars.make_text Loc.none "--build=x86_64-w64-mingw32")
+ (* XXX(steve): this might also be mingw-specific, as it's [round] function apparently does not work *)
+ :: Literal
+ (String_with_vars.make_text Loc.none "--enable-imprecise-c99-float-ops")
+ :: args)
+ | _ -> action)
+ | other -> other
+;;
+
let modify_build_action ~prefix action =
let+ installed = Fs_memo.dir_exists prefix in
if installed
@@ -190,6 +248,8 @@ let modify_build_action ~prefix action =
(* If the toolchain is already installed, just create config.cache file.
TODO(steve): Move this check to action execution time *)
touch_config_cache
+ else if Sys.win32
+ then modify_build_action_windows action
else action
;;
diff --git a/src/dune_util/build_path_prefix_map0.ml b/src/dune_util/build_path_prefix_map0.ml
index e7c23b5eb..97797644a 100644
--- a/src/dune_util/build_path_prefix_map0.ml
+++ b/src/dune_util/build_path_prefix_map0.ml
@@ -4,11 +4,18 @@ let _BUILD_PATH_PREFIX_MAP = "BUILD_PATH_PREFIX_MAP"
let extend_build_path_prefix_map env how map =
let new_rules = Build_path_prefix_map.encode_map map in
- Env.update env ~var:_BUILD_PATH_PREFIX_MAP ~f:(function
- | None -> Some new_rules
- | Some existing_rules ->
- Some
- (match how with
- | `Existing_rules_have_precedence -> new_rules ^ ":" ^ existing_rules
- | `New_rules_have_precedence -> existing_rules ^ ":" ^ new_rules))
+ (* XXX(steve): this was causing problems building ocaml-base-compiler on
+ windows, so skip it for now. When the BUILD_PATH_PREFIX_MAP variable is
+ set on windows, the compiler fails to compile with the following error:
+ "Fatal error: Invalid value for the environment variable BUILD_PATH_PREFIX_MAP: invalid key/value pair "C", no '=' separator" *)
+ let _ =
+ Env.update env ~var:_BUILD_PATH_PREFIX_MAP ~f:(function
+ | None -> Some new_rules
+ | Some existing_rules ->
+ Some
+ (match how with
+ | `Existing_rules_have_precedence -> new_rules ^ ":" ^ existing_rules
+ | `New_rules_have_precedence -> existing_rules ^ ":" ^ new_rules))
+ in
+ env
;; |
When building the compiler package (ocaml-base-compiler), dune modifies its build and install commands so that the compiler is installed to a user-wide toolchains directory (~/.cache/dune/toolchains) rather than inside the _build directory. Currently the modifications to the build and install commands are specific to unix, and don't work on windows.
We should modify the commands in such a way that they work on both unix and windows, or (more likely) use alternative commands on windows that are specific to that platform.
The text was updated successfully, but these errors were encountered: