forked from Mercury-Language/mercury
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Makefile.DLLs
197 lines (170 loc) · 7.2 KB
/
Makefile.DLLs
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
#-----------------------------------------------------------------------------#
# Copyright (C) 1997-1998 The University of Melbourne.
# This file may only be copied under the terms of the GNU General
# Public Licence - see the file COPYING in the Mercury distribution.
#-----------------------------------------------------------------------------#
# Makefile.DLLs, version 0.5b.
# This Makefile contains rules for creating DLLs on Windows using gnu-win32.
#-----------------------------------------------------------------------------#
# The SYM_PREFIX is used as a prefix for the symbols in the files
# that this makefile automatically generates.
#
# The default SYM_PREFIX for libfoo.dll is `libfoo'.
# But you can override this by setting `SYM_PREFIX-libfoo = blah'.
SYM_PREFIX = $(firstword $(SYM_PREFIX-$*) $*)
GUARD_MACRO = $(SYM_PREFIX)_GLOBALS_H
DEFINE_DLL_MACRO = $(SYM_PREFIX)_DEFINE_DLL
USE_DLL_MACRO = $(SYM_PREFIX)_USE_DLL
IMP_MACRO = $(SYM_PREFIX)_IMP
GLOBAL_MACRO = $(SYM_PREFIX)_GLOBAL
IMPURE_PTR = $(SYM_PREFIX)_impure_ptr
# You should change your rule for creating `foo.a' to instead
# create `foo$(DLL_DEF_LIB).a'. Then this makefile will create
# `foo.a' from `foo_def.a'.
DLL_DEF_LIB = _def
# This rule creates a `.def' file, which lists the symbols that are exported
# from the DLL. We use `nm' to get a list of all the exported text (`T')
# symbols and data symbols -- including uninitialized data (`B'),
# initialized data (`D'), read-only data (`R'), and common blocks (`C').
# We also export `_impure_ptr', suitably renamed, so that the
# main program can do the necessary initialization of the DLL's _impure_ptr.
# (Since there can be more than one DLL, we must rename _impure_ptr as
# $(SYM_PREFIX)_impure_ptr to prevent name collisions.)
%.def: %_def.a
echo EXPORTS > $@
echo $(IMPURE_PTR) = _impure_ptr >> $@
nm $< | sed -n '/^........ [BCDRT] _/s/[^_]*_//p' >> $@
# We need to use macros to access global data:
# the user of the DLL must refer to `bar' as `(*__imp_bar)'.
# This rule creates a pair of files `foo_dll.h' and `foo_globals.h'
# which contains macros for doing this.
#
# The DLL may also contain some references to _impure_ptr
# (e.g. stdin is defined as a macro which expands to _impure_ptr.stdin).
# We need to provide a definition for this (otherwise it will link in
# the definition in libccrt.o, which causes lots of problems,
# eventually leading to undefined symbol `WinMain').
# The main program needs to initialize all the _impure_ptr variables
# for the DLLs with its _impure_ptr.
%_dll.h:
echo "/* automatically generated by Makefile.DLLs */" > $@
echo "#ifndef $(GUARD_MACRO)" >> $@
echo "#define $(GUARD_MACRO)" >> $@
echo "" >> $@
echo "#if defined(__GNUC__) && defined(__CYGWIN32__)" >> $@
echo " #if !defined($(DEFINE_DLL_MACRO))" >> $@
echo " #define $(IMP_MACRO)(name) __imp_##name" >> $@
echo " #define $(GLOBAL_MACRO)(name) (*$(IMP_MACRO)(name))" >> $@
echo " #include \"$*_globals.h\"" >> $@
echo " #endif /* $(DEFINE_DLL_MACRO) */" >> $@
echo "#endif /* __GNUC__ && __CYGWIN32__ */" >> $@
echo "" >> $@
echo "#endif /* $(GUARD_MACRO) */" >> $@
%_globals.h: %_def.a
echo "/* automatically generated by Makefile.DLLs */" > $@
for sym in $(IMPURE_PTR) \
`nm $< | grep '^........ [BCDR] _' | sed 's/[^_]*_//'`; \
do \
echo "#define $$sym $(GLOBAL_MACRO)($$sym)" >> $@; \
done
%_dll.c:
echo "/* automatically generated by Makefile.DLLs */" > $@
echo "void *_impure_ptr;" >> $@
# This rule creates the export object file (`foo.exp') which contains the
# jump table array; this export object file becomes part of the DLL.
# This rule also creates the import library (`foo.a') which contains small
# stubs for all the functions exported by the DLL which jump to them via the
# jump table. Executables that will use the DLL must be linked against this
# stub library.
%.exp %.a : %.def
dlltool $(DLLTOOLFLAGS) $(DLLTOOLFLAGS-$*) \
--def $< \
--dllname $*.dll \
--output-exp $*.exp \
--output-lib $*.a
# The `sed' commands below are to convert DOS-style `C:\foo\bar'
# pathnames into Unix-style `//c/foo/bar' pathnames.
CYGWIN32_LIBS = $(shell echo \
-L`dirname \`gcc -print-file-name=libgcc.a | \
sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
-L`dirname \`gcc -print-file-name=libcygwin.a | \
sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
-L`dirname \`gcc -print-file-name=libkernel32.a | \
sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
-lgcc -lcygwin -lkernel32 -lgcc)
# Making relocatable DLLs doesn't seem to work.
# Note quite sure why. The --image-base values below
# where chosen at random, the first two at least seem to work on my machine.
RELOCATABLE=no
LDFLAGS-libgc += --image-base=0x2345000
LDFLAGS-libmer_rt += --image-base=0x1234000
LDFLAGS-libmer_std += --image-base=0x3456000
LDFLAGS-libmer_trace += --image-base=0x4567000
LDFLAGS-libmer_browser += --image-base=0x5678000
ifeq "$(strip $(RELOCATABLE))" "yes"
# to create relocatable DLLs, we need to do two passes
# (warning: this is untested)
%.dll: %.exp %_def.a %_dll.o dll_init.o dll_fixup.o
$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $*.base \
-e _dll_entry@12 \
$*.exp $*_def.a $*_dll.o \
dll_init.o dll_fixup.o \
$(LDLIBS) $(LDLIBS-$*) \
$(CYGWIN32_LIBS)
# untested
dlltool $(DLLTOOLFLAGS) $(DLLTOOLFLAGS-$*) \
--def $*.def \
--dllname $*.dll \
--base-file $*.base \
--output-exp $*.exp
$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $*.base \
-e _dll_entry@12 \
$*.exp $*_def.a $*_dll.o \
dll_init.o dll_fixup.o \
$(LDLIBS) $(LDLIBS-$*) \
$(CYGWIN32_LIBS)
dlltool $(DLLTOOLFLAGS) $(DLLTOOLFLAGS-$*) \
--def $*.def \
--dllname $*.dll \
--base-file $*.base \
--output-exp $*.exp
# end untested stuff
$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll --base-file $*.base -o $@ \
-e _dll_entry@12 \
$*.exp $*_def.a $*_dll.o \
dll_init.o dll_fixup.o \
$(LDLIBS) $(LDLIBS-$*) \
$(CYGWIN32_LIBS)
rm -f $*.base
else
%.dll: %.exp %_def.a %_dll.o dll_fixup.o dll_init.o
$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $@ \
-e _dll_entry@12 \
$*.exp $*_def.a $*_dll.o \
dll_init.o dll_fixup.o \
$(LDLIBS) $(LDLIBS-$*) \
$(CYGWIN32_LIBS)
endif
# This black magic piece of assembler needs to be linked in in order to
# properly terminate the list of imported DLLs.
dll_fixup.s:
echo '.section .idata$$3' > dll_fixup.s
echo '.long 0,0,0,0, 0,0,0,0' >> dll_fixup.s
dll_fixup.o: dll_fixup.s
$(AS) $(ASFLAGS) -o dll_fixup.o dll_fixup.s
# Windows requires each DLL to have an initialization function
# that is called at certain points (thread/process attach/detach).
# This one just doesn't do anything.
dll_init.c:
echo '__attribute__((stdcall))' > dll_init.c
echo 'int dll_entry(int handle, int reason, void *ptr)' >> dll_init.c
echo '{ return 1; }' >> dll_init.c
# The following rule is just there to convince gcc
# to keep otherwise unused intermediate targets around.
dont_throw_away: dll_fixup.o dll_init.o
.PHONY: clean
clean: clean_dll
.PHONY: clean_dll
clean_dll:
-rm -f dll_init.c dll_init.o dll_fixup.s dll_fixup.o
#-----------------------------------------------------------------------------#