Skip to content
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

Building O'Caml 3.09.0 with MSVC 2005 #3858

Closed
vicuna opened this issue Nov 11, 2005 · 2 comments
Closed

Building O'Caml 3.09.0 with MSVC 2005 #3858

vicuna opened this issue Nov 11, 2005 · 2 comments
Labels

Comments

@vicuna
Copy link

vicuna commented Nov 11, 2005

Original bug ID: 3858
Reporter: administrator
Status: closed (set by @xavierleroy on 2005-11-21T14:15:23Z)
Resolution: not a bug
Priority: normal
Severity: minor
Category: ~DO NOT USE (was: OCaml general)

Bug description

I just built O'Caml with the MSVC toolchain, and want to report my
experiences. It seems O'Caml need to be changed to catch up with the
newest features of MSVC.

I did this with

  • Visual Studio 2005 (Version 8.0) Express Edition
  • Platform SDK for Windows 2003 (that works also for XP)
  • MASM 6.14, extracted from the "MASM32" installation
    (one needs only ml.exe and ml.err)

on a Windows XP system. The Express Edition is a free download, so this
build is quite interesting for the community.

First of all, the installed compiler and linker do not find the system
header files and the lib files (i.e. those of VC itself and those of the
Platform SDK). There are no instructions by Microsoft how to fix that
for the command-line tools, only for the IDE. So I had to work around
that.

I created a small script gps_cl.bat:

@echo off
cl %* "@c:\programme\microsoft visual studio 8\vc\vcopts.txt" "@d:\programme\microsoft platform sdk\vcopts.txt"

The two vcopts.txt files are also my invention, and they contain the
necessary /I and /link options:

"/Ic:\programme\microsoft visual studio 8\vc\include" /link "/libpath:c:\programme\microsoft visual studio 8\vc\lib"

and

"/Id:\programme\microsoft platform sdk\include" /link "/libpath:d:\programme\microsoft platform sdk\lib"

The point is that I must put the /link options in response files,
otherwise the argument list of cl becomes wrong. Furthermore, the /I
options must be appended to the user-supplied options. The reason is
that there is also a memory.h by Microsoft, so if one does not append,
the wrong memory.h will be used during the build.

Microsoft now uses versioned DLLs for the VC libraries, at least on
Windows XP and Windows 2003. This breaks the whole O'Caml build. When
one compiles an .exe and refers to one of the VC libraries, not only
the .exe but also a second file .exe.manifest is created. This file
contains the information which DLLs (now called "assemblies" - .NET
speech) must be used.

There are two kinds of manifests: external manifests like the generated
file, and internal manifests that are embedded into PE files. The
documentation says the external manifest is enough - actually, this is
not true. If one executes the program one gets the error that a required
DLL is not found. Embedded manifests work, however, and they have the
advantage that one needs not to install the second file into the final
location. To embed the manifest, one must run

mt -outputresource:.exe -manifest .exe.manifest

(Yes, these are Unix -switches!)

The same for DLLs. Sometimes the manifest is not created, and I
interpret this as it is not needed. Sometimes one cannot run the program
after embedding if the external manifest exists.

The manifest works on the computer where one built the program. After
deployment elsewhere one might need a different manifest; this depends
on how the referenced DLLs are deployed. The embedded manifest can be
later changed, so this is not an issue for the O'Caml build.

Of course, I had to change a lot of things to cope with the manifests. I
attach the config/Makefile and the diffs. The mt tool is automatically
run by the O'Caml driver if the manifest file appears.

Finally, I had problems building on a network drive: stdlib.cmxa began
with 128k zeros. May be a Windows error or a Samba error.

The VC compiler outputs several warnings:

  • /DEBUGTYPE:CV is no longer supported
  • -o is deprecated and will be removed

I think the best solution would be a self-written driver for cl that
accepts POSIX options and translates them into the equivalent cl
options. And where linker options are passed with -Wl and not with the
sick /link option. And that calls mt when necessary.

Another small problem: ocamlwin.exe does not work without registry
entry. The docs says in this case it asks the user. This does not work
("Cannot find ocaml.exe. I quit.").

Gerd

---------------------- config/Makefile ------------------------

#########################################################################

Objective Caml

Xavier Leroy, projet Cristal, INRIA Rocquencourt

Copyright 1999 Institut National de Recherche en Informatique et

en Automatique. All rights reserved. This file is distributed

under the terms of the GNU Library General Public License, with

the special exception on linking described in file ../LICENSE.

#########################################################################

$Id: Makefile.msvc,v 1.14 2005/08/01 15:51:09 xleroy Exp $

Configuration for Windows, Visual C++ compiler

######### General configuration

PREFIX=D:/programme/ocamlms

Where to install the binaries.

BINDIR=$(PREFIX)/bin

Where to install the standard library

LIBDIR=$(PREFIX)/lib

Where to install the stub DLLs

STUBLIBDIR=$(LIBDIR)/stublibs

Where to install the info files

DISTRIB=$(PREFIX)

########## Toolchain and OS dependencies

TOOLCHAIN=msvc
CCOMPTYPE=msvc
O=obj
A=lib
S=asm
SO=s.obj
DO=d.obj
EXE=.exe

########## Configuration for the bytecode compiler

#MSVC_CFLAGS='@c:\programme\microsoft visual studio 8\vc\vcopts.txt' \

'@d:\programme\microsoft platform sdk\vcopts.txt'

MSVC_CFLAGS=

MSVC_LDFLAGS='/LIBPATH:c:\programme\microsoft visual studio 8\vc\lib'
'/LIBPATH:d:\programme\microsoft platform sdk\lib'

Which C compiler to use for the bytecode interpreter.

BYTECC=gps_cl.bat /nologo $(MSVC_CFLAGS)

Additional compile-time options for $(BYTECC). (For static linking.)

BYTECCCOMPOPTS=/Ox /MT

Additional link-time options for $(BYTECC). (For static linking.)

BYTECCLINKOPTS=/MT

Additional compile-time options for $(BYTECC). (For building a DLL.)

DLLCCCOMPOPTS=/Ox /MD -DCAML_DLL

Libraries needed

BYTECCLIBS=advapi32.lib
NATIVECCLIBS=advapi32.lib

How to invoke the C preprocessor

CPP=gps_cl.bat /nologo /EP

New: How to build an executable

MKEXE=$(BYTECC) -o $(1) $(2) &&
mt -nologo -outputresource:$(1) -manifest $(1).manifest

How to build a DLL

MKDLL=link /nologo /dll $(MSVC_LDFLAGS) /out:$(1) /implib:$(2) $(3) &&
mt -nologo -outputresource:$(1) -manifest $(1).manifest

How to build a static library

MKLIB=link /lib /nologo $(MSVC_LDFLAGS) /debugtype:CV /out:$(1) $(2)

Canonicalize the name of a system library

SYSLIB=$(1).lib

The ranlib command

RANLIBCMD=

############# Configuration for the native-code compiler

Name of architecture for the native-code compiler

ARCH=i386

Name of architecture model for the native-code compiler.

MODEL=default

Name of operating system family for the native-code compiler.

SYSTEM=win32

Which C compiler to use for the native-code compiler.

NATIVECC=gps_cl.bat /nologo $(MSVC_CFLAGS)

Additional compile-time options for $(NATIVECC).

NATIVECCCOMPOPTS=/Ox /MT

Additional link-time options for $(NATIVECC)

NATIVECCLINKOPTS=/MT

Build partially-linked object file

PARTIALLD=lib /nologo /debugtype:cv
PACKLD=ld -r --oformat pe-i386

############# Configuration for the contributed libraries

OTHERLIBRARIES=win32unix systhreads str num win32graph dynlink bigarray labltk

Name of the target architecture for the "num" library

BNG_ARCH=generic
BNG_ASM_LEVEL=0

Configuration for LablTk

Set TK_ROOT to the directory where you installed TCL/TK 8.3

TK_ROOT=d:/programme/tcl
TK_DEFS=-I$(TK_ROOT)/include

The following definition avoids hard-wiring $(TK_ROOT) in the libraries

produced by OCaml, and is therefore required for binary distribution

of these libraries. However, $(TK_ROOT) must be added to the LIB

environment variable, as described in README.win32.

TK_LINK=tk83.lib tcl83.lib

An alternative definition that avoids mucking with the LIB variable,

but hard-wires the Tcl/Tk location in the binaries

TK_LINK=$(TK_ROOT)/lib/tk83.lib $(TK_ROOT)/lib/tcl83.lib

############# Aliases for common commands

MAKEREC=$(MAKE) -f Makefile.nt
MAKECMD=$(MAKE)

-------------------------- patch ------------------------------

--- ./asmcomp/asmlink.ml.orig 2005-11-11 13:14:28.000000000 +0100
+++ ./asmcomp/asmlink.ml 2005-11-11 15:07:22.000000000 +0100
@@ -229,51 +229,69 @@
raise(Error(File_not_found libname)) in
let c_lib =
if !Clflags.nopervasives then "" else Config.native_c_libraries in

  • let cmd =
  • let cmds =
    match Config.ccomp_type with
    "cc" ->
    if not !Clflags.output_c_object then
  •      Printf.sprintf "%s %s -o %s %s %s %s %s %s %s %s %s"
    
  •        !Clflags.c_linker
    
  •        (if !Clflags.gprofile then Config.cc_profile else "")
    
  •        (Filename.quote output_name)
    
  •        (Clflags.std_include_flag "-I")
    
  •        (String.concat " " (List.rev !Clflags.ccopts))
    
  •        (Filename.quote startup_file)
    
  •        (Ccomp.quote_files (List.rev file_list))
    
  •        (Ccomp.quote_files
    
  •          (List.map (fun dir -> if dir = "" then "" else "-L" ^ dir)
    
  •                    !load_path))
    
  •        (Ccomp.quote_files (List.rev !Clflags.ccobjs))
    
  •        (Filename.quote runtime_lib)
    
  •        c_lib
    
  •      [ (fun () -> true),
    
  •        Printf.sprintf "%s %s -o %s %s %s %s %s %s %s %s %s"
    
  •          !Clflags.c_linker
    
  •          (if !Clflags.gprofile then Config.cc_profile else "")
    
  •          (Filename.quote output_name)
    
  •          (Clflags.std_include_flag "-I")
    
  •          (String.concat " " (List.rev !Clflags.ccopts))
    
  •          (Filename.quote startup_file)
    
  •          (Ccomp.quote_files (List.rev file_list))
    
  •          (Ccomp.quote_files
    
  •            (List.map (fun dir -> if dir = "" then "" else "-L" ^ dir)
    
  •                      !load_path))
    
  •          (Ccomp.quote_files (List.rev !Clflags.ccobjs))
    
  •          (Filename.quote runtime_lib)
    
  •          c_lib
    
  • ]
       else
    
  •      Printf.sprintf "%s -o %s %s %s"
    
  •        Config.native_partial_linker
    
  •        (Filename.quote output_name)
    
  •        (Filename.quote startup_file)
    
  •        (Ccomp.quote_files (List.rev file_list))
    
  •      [ (fun () -> true),
    
  •        Printf.sprintf "%s -o %s %s %s"
    
  •          Config.native_partial_linker
    
  •          (Filename.quote output_name)
    
  •          (Filename.quote startup_file)
    
  •          (Ccomp.quote_files (List.rev file_list))
    
  • ]
    
    | "msvc" ->
    if not !Clflags.output_c_object then
  •      Printf.sprintf "%s /Fe%s %s %s %s %s %s %s %s"
    
  •        !Clflags.c_linker
    
  •        (Filename.quote output_name)
    
  •        (Clflags.std_include_flag "-I")
    
  •        (Filename.quote startup_file)
    
  •        (Ccomp.quote_files (List.rev file_list))
    
  •        (Ccomp.quote_files 
    
  •          (List.rev_map Ccomp.expand_libname !Clflags.ccobjs))
    
  •        (Filename.quote runtime_lib)
    
  •        c_lib
    
  •        (String.concat " " (List.rev !Clflags.ccopts))
    
  • [ (fun () -> true),
    
  •        Printf.sprintf "%s /Fe%s %s %s %s %s %s %s %s"
    
  •          !Clflags.c_linker
    
  •          (Filename.quote output_name)
    
  •          (Clflags.std_include_flag "-I")
    
  •          (Filename.quote startup_file)
    
  •          (Ccomp.quote_files (List.rev file_list))
    
  •          (Ccomp.quote_files 
    
  •            (List.rev_map Ccomp.expand_libname !Clflags.ccobjs))
    
  •          (Filename.quote runtime_lib)
    
  •          c_lib
    
  •          (String.concat " " (List.rev !Clflags.ccopts));
    
  •   (fun () -> Sys.file_exists(output_name ^ ".manifest")),
    
  •   Printf.sprintf
    
  •     "mt -nologo -outputresource:%s -manifest %s.manifest"
    
  •     (Filename.quote output_name)
    
  •     (Filename.quote output_name)
    
  • ]
       else
    
  •      Printf.sprintf "%s /out:%s %s %s"
    
  •        Config.native_partial_linker
    
  •        (Filename.quote output_name)
    
  •        (Filename.quote startup_file)
    
  •        (Ccomp.quote_files (List.rev file_list))
    
  •      [ (fun () -> true),
    
  •         Printf.sprintf "%s /out:%s %s %s"
    
  •          Config.native_partial_linker
    
  •          (Filename.quote output_name)
    
  •          (Filename.quote startup_file)
    
  •          (Ccomp.quote_files (List.rev file_list))
    
  • ]
    
    | _ -> assert false
  • in if Ccomp.command cmd <> 0 then raise(Error Linking_error)
  • in
  • List.iter
  • (fun (cond,cmd) ->
  •   if cond() then
    
  •     if Ccomp.command cmd <> 0 then raise(Error Linking_error))
    
  • cmds

let object_file_name name =
let file_name =
--- ./bytecomp/bytelink.ml.orig 2005-11-11 13:01:39.000000000 +0100
+++ ./bytecomp/bytelink.ml 2005-11-11 15:04:49.000000000 +0100
@@ -469,7 +469,14 @@
file is created in the current working directory. *)
remove_file
(Filename.chop_suffix (Filename.basename prim_name) ".c" ^ ".obj");

  •  retcode
    
  •  if retcode = 0 && Sys.file_exists (exec_name ^ ".manifest") then
    
  •    Ccomp.command
    
  • (Printf.sprintf
    
  •   "mt -nologo -outputresource:%s -manifest %s.manifest" 
    
  •   (Filename.quote exec_name)
    
  •   (Filename.quote exec_name))
    
  •  else
    
  •    retcode
    
    | _ -> assert false

let append_bytecode_and_cleanup bytecode_name exec_name prim_name =
--- ./byterun/Makefile.nt.orig 2005-11-11 12:33:36.000000000 +0100
+++ ./byterun/Makefile.nt 2005-11-11 12:44:32.000000000 +0100
@@ -40,7 +40,8 @@
all: ocamlrun.exe libcamlrun.$(A)

ocamlrun.exe: ocamlrun.dll main.$(DO)

  • $(CC) -o ocamlrun.exe main.$(DO) ocamlrun.$(A)
  • #$(CC) -o ocamlrun.exe main.$(DO) ocamlrun.$(A)
  • $(call MKEXE,ocamlrun.exe,main.$(DO) ocamlrun.$(A))

ocamlrun.dll: $(DOBJS)
$(call MKDLL,ocamlrun.dll,ocamlrun.$(A),$(DOBJS) $(BYTECCLIBS))
--- ./win32caml/Makefile.orig 2005-11-11 15:16:45.000000000 +0100
+++ ./win32caml/Makefile 2005-11-11 15:19:14.000000000 +0100
@@ -17,6 +17,7 @@

CC=$(BYTECC)
CFLAGS=$(BYTECCCOMPOPTS)
+RCFLAGS=/I 'd:\programme\microsoft platform sdk\include'

OBJS=startocaml.$(O) ocamlres.$(O) ocaml.$(O) menu.$(O)
history.$(O) editbuffer.$(O)
@@ -31,8 +32,8 @@

ocamlres.$(O): ocaml.rc ocaml.ico
ifeq ($(TOOLCHAIN),msvc)

  • rc ocaml.rc
  • cvtres /nologo /machine:ix86 /out:$@ ocaml.res
  • rc $(RCFLAGS) ocaml.rc
  • cvtres /nologo /machine:ix86 /out:$@ ocaml.RES
    rm -f ocaml.res
    endif
    ifeq ($(TOOLCHAIN),mingw)
    --- ./otherlibs/labltk/browser/Makefile.nt.orig 2005-10-17 02:43:27.000000000 +0200
    +++ ./otherlibs/labltk/browser/Makefile.nt 2005-11-11 17:46:40.782856603 +0100
    @@ -9,7 +9,7 @@
    ifeq ($(CCOMPTYPE),cc)
    WINDOWS_APP=-ccopt "-Wl,--subsystem,windows"
    else
    -WINDOWS_APP=-ccopt "/link /subsystem:windows"
    +WINDOWS_APP=-ccopt " @linkopts"
    endif

OBJS = list2.cmo useunix.cmo setpath.cmo lexical.cmo
@@ -39,12 +39,15 @@

ocamlbrowser.exe: $(TOPDIR)/toplevel/toplevellib.cma
../support/lib$(LIBNAME).$(A)
-ocamlbrowser.exe: jglib.cma $(OBJS) winmain.$(O)
+ocamlbrowser.exe: jglib.cma $(OBJS) winmain.$(O) linkopts
$(CAMLC) -o ocamlbrowser.exe -custom $(INCLUDES)
$(TOPDIR)/toplevel/toplevellib.cma
unix.cma threads.cma str.cma $(LIBNAME).cma jglib.cma $(OBJS)
winmain.$(O) $(WINDOWS_APP)

+linkopts:

  •   echo "/link /subsystem:windows" >linkopts
    

jglib.cma: $(JG)
$(CAMLCOMP) -a -o jglib.cma $(JG)

--

Gerd Stolpmann * Viktoriastr. 45 * 64293 Darmstadt * Germany
gerd@gerd-stolpmann.de http://www.gerd-stolpmann.de
Telefon: 06151/153855 Telefax: 06151/997714

@vicuna
Copy link
Author

vicuna commented Nov 21, 2005

Comment author: @xavierleroy

Dear Gerd,

I just built O'Caml with the MSVC toolchain, and want to report my
experiences. It seems O'Caml need to be changed to catch up with the
newest features of MSVC.

Your message reminded me of everything I hate with developing under
Windows :-)

The root of your problem is this:

I did this with

  • Visual Studio 2005 (Version 8.0) Express Edition
  • Platform SDK for Windows 2003 (that works also for XP)
  • MASM 6.14, extracted from the "MASM32" installation
    (one needs only ml.exe and ml.err)

on a Windows XP system. The Express Edition is a free download, so this
build is quite interesting for the community.

You should have used the free download of the Visual C++ compiler (the
classic one, not this awful .Net environment). That's what I use for
building the binary OCaml distribution, and the Makefiles are set up
for that. You'll also need the Platform SDK, MASM, and a fourth
package whose name escapes me at the moment. I should have taken
notes and published them on the Web.

First of all, the installed compiler and linker do not find the system
header files and the lib files (i.e. those of VC itself and those of the
Platform SDK). There are no instructions by Microsoft how to fix that
for the command-line tools, only for the IDE. So I had to work around
that.

I created a small script gps_cl.bat:

@echo off
cl %* "@c:\programme\microsoft visual studio 8\vc\vcopts.txt" "@d:\programme\microsoft platform sdk\vcopts.txt"

The two vcopts.txt files are also my invention, and they contain the
necessary /I and /link options:

"/Ic:\programme\microsoft visual studio 8\vc\include" /link "/libpath:c:\programme\microsoft visual studio 8\vc\lib"

and

"/Id:\programme\microsoft platform sdk\include" /link "/libpath:d:\programme\microsoft platform sdk\lib"

The point is that I must put the /link options in response files,
otherwise the argument list of cl becomes wrong. Furthermore, the /I
options must be appended to the user-supplied options. The reason is
that there is also a memory.h by Microsoft, so if one does not append,
the wrong memory.h will be used during the build.

The standard way to address these problems is to set the LIB and
INCLUDE environment variables to the search paths for .lib and .h
files, respectively. This can be done either via the control panel,
"System" tool, or (if you're calling everything from a Cygwin shell)
using Cygwin environment variables.

Microsoft now uses versioned DLLs for the VC libraries, at least on
Windows XP and Windows 2003. This breaks the whole O'Caml build.

.Net revisionism! Fortunately, non-versioned DLLs are still supported
by the non-.Net tools.

Best wishes,

  • Xavier

@vicuna
Copy link
Author

vicuna commented Nov 21, 2005

Comment author: @xavierleroy

Will not support .Net compilers. Supporting Visual C++ compilers is enough work already.

@vicuna vicuna closed this as completed Nov 21, 2005
@vicuna vicuna added the bug label Mar 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant