Rombobjörn

summaryrefslogtreecommitdiff
path: root/comfignat.mk
blob: c9a34b674501b5350ea5e72f0ff1b98512594713 (plain)
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# Comfignat makefile foundation for configuring and building GNAT projects
# Copyright 2013 B. Persson, Bjorn@Rombobeorn.se
#
# This material is provided as is, with absolutely no warranty expressed
# or implied. Any use is at your own risk.
#
# Permission is hereby granted to use or copy this makefile
# for any purpose, provided the above notices are retained on all copies.
# Permission to modify the code and to distribute modified code is granted,
# provided the above notices are retained, and a notice that the code was
# modified is included with the above copyright notice.


# This file contains generic Make code. It is designed to be included by other
# makefiles, called containing makefiles, which add information specific to the
# project at hand. Builds are controlled by GNAT project files which import the
# abstract project Comfignat and use the directory variables it defines. For
# libraries there shall also be usage projects to be installed on the target
# system. Usage projects and the Comfignat project will be preprocessed with
# Gnatprep. (Build projects may also be preprocessed.)
#
# If a directories project is provided, then the project files will get the
# directory variables from there, otherwise the Make variables will be used.
#
# This file may not work with other Make clones than GNU Make. (Reusable Make
# code is pretty much impossible to write without advanced Make features.) If
# Make cannot be used for whatever reason, then it's not too difficult to run
# the project files through Gnatprep manually.


#
# Program-name variables and the usual options variables are picked up from the
# environment or the command line:
#

GNATPREP     ?= gnatprep
GNAT_BUILDER ?= gprbuild

# If GNAT_BUILDER looks like it will invoke Gnatmake, then make the default
# value of GNATFLAGS compatible with Gnatmake. Otherwise make it suitable for
# building multi-language projects with GPRbuild.
GNATFLAGS ?= ${if ${findstring gnatmake, \
                               ${notdir ${call mung,${GNAT_BUILDER}}}}, \
                  ${GNAT_BUILDER_FLAGS} \
                     -cargs ${ADAFLAGS} \
                     -bargs ${GNATBINDFLAGS} \
                     -largs ${GNATLINKFLAGS} ${LDFLAGS}, \
                  ${GNAT_BUILDER_FLAGS} \
                     -cargs:Ada ${ADAFLAGS} \
                     -cargs:C ${CPPFLAGS} ${CFLAGS} \
                     -cargs:C++ ${CPPFLAGS} ${CXXFLAGS} \
                     -cargs:Fortran ${FFLAGS} \
                     -bargs ${GNATBINDFLAGS} \
                     -largs ${LDFLAGS}}

# (DESTDIR is also supported.)

# Containing makefiles may assign default values to the options variables
# GNAT_BUILDER_FLAGS, ADAFLAGS, CFLAGS, CXXFLAGS, FFLAGS, GNATBINDFLAGS,
# GNATLINKFLAGS and LDFLAGS if they are undefined in the environment, but
# should expect that users and distributions may override those defaults.


#
# These variables should be overridden on the command line as needed, but will
# not be picked up from the environment:
#

dirgpr =
# dirgpr should be the filename of the target system's directories project if
# there is one. The Gnatprep symbols Directories_GPR and Directories_Project
# will be derived from dirgpr, and project files will be configured to use the
# directories project.

prefix        = /usr/local
exec_prefix   = ${prefix}
bindir        = ${exec_prefix}/bin
libexecdir    = ${exec_prefix}/libexec
datarootdir   = ${prefix}/share
datadir       = ${datarootdir}
sysconfdir    = ${prefix}/etc
localstatedir = ${prefix}/var
includedir    = ${prefix}/include
libdir        = ${exec_prefix}/lib
gprdir        = ${datarootdir}/gpr
localedir     = ${datarootdir}/locale
mandir        = ${datarootdir}/man
infodir       = ${datarootdir}/info
# These are the directories where different kinds of files will be installed on
# the target system. Some of these directory variables aren't used in this file
# but may be needed in containing makefiles.

builddir = ${CURDIR}/build
objdir   = ${builddir}/obj
stagedir = ${builddir}/stage
# Intermediate files produced during the build are kept in objdir. Files to be
# installed are written to stagedir, and then copied to their destination in
# the installation step.

# Containing makefiles should avoid modifying the directory variables. Users
# should be able to rely on these defaults.

relocatable_package = false
# If relocatable_package is true, then directory variables in project files
# will be configured with relative pathnames so that the installed directory
# tree as a whole can be moved to another location in the filesystem without
# breaking the project files.
# dirgpr takes precedence over relocatable_package.

install_cp_flags = ${if ${DESTDIR},--preserve=timestamps,}
# Timestamps are preserved when installation is done to a staging directory. 
# This matters for files that aren't generated during the build but copied from
# the source tree. Timestamps are not preserved when installation is done
# directly to the target system, because that would change the timestamps of 
# existing directories.


#
# Containing makefiles should assign or append to these variables as needed:
#

configuration_variables += \
   GNATPREP GNAT_BUILDER GNAT_BUILDER_FLAGS ADAFLAGS CPPFLAGS CFLAGS CXXFLAGS \
   FFLAGS GNATBINDFLAGS GNATLINKFLAGS LDFLAGS GNATFLAGS DESTDIR \
   dirgpr prefix exec_prefix bindir libexecdir datarootdir datadir sysconfdir \
   localstatedir includedir libdir gprdir localedir mandir infodir builddir \
   objdir stagedir relocatable_package install_cp_flags
# configuration_variables is a list of variables that can be saved in the
# persistent configuration with "make configure". Containing makefiles may
# append additional variable names.

ifneq (${origin preprocessed_files},file)
   preprocessed_files := ${basename ${wildcard *.in}}
endif
# preprocessed_files is a list of files to be produced in the preprocessing
# step at the beginning of the build. Containing makefiles may override it or
# append additional filenames to it.

ifneq (${origin build_GPRs},file)
   build_GPRs :=
endif
# build_GPRs shall name one or more project files for building the software.
# These project files will be used when "make" or "make build" is invoked.

ifneq (${origin usage_GPRs},file)
   usage_GPRs :=
endif
# If the build produces libraries, then usage_GPRs shall name the project files
# that other projects should import to link to the libraries. These project
# files will be installed to the target system.

ifneq (${origin options},file)
   options :=
endif
# options may be assigned a list of variable names. Those variables may be
# overridden on the command line, and will be defined as Gnatprep symbols.
# Their values must be "true" or "false".
# The containing makefile should assign a default value to each variable unless
# it shall be mandatory to always set the option on the command line.

ifneq (${origin Gnatprep_definitions},file)
   Gnatprep_definitions :=
endif
# Any text assigned to Gnatprep_definitions will be included in the Gnatprep
# command line. It may be used for additional symbol definitions.


#
# Containing makefiles may use this command variable:
#

build_GPR = "${GNAT_BUILDER}" -P ${firstword ${filter %.gpr,$^}} -p \
            ${GNATFLAGS} -margs
# build_GPR is a command for use in recipies. It performs a build controlled by
# the first project file among the rule's prerequisites.
# Containing makefiles may append additional arguments for the builder, but
# should ensure that any arguments that aren't essential for the build to work
# can be overridden from the command line. Global default values for optional
# arguments should be set in the options variables instead.


#
# Read the configuration file if there is one:
#

-include comfignat_configuration.mk


#
# Compute the symbol definitions for Gnatprep, and some other data that the
# rules need:
#

nil =
space_sub = _Comfignat_magic_protective_space_character_substitute_
percent_sub = _Comfignat_magic_protective_percent_character_substitute_
mung = ${subst %,${percent_sub},${subst ${nil} ,${space_sub},${1}}}
unmung = ${subst ${percent_sub},%,${subst ${space_sub}, ,${1}}}
# mung and unmung are used to prevent Make from interpreting space and percent
# characters in strings.

# Convey objdir and stagedir to Gnatprep.
directories := '-DObjdir="${objdir}"' '-DStagedir="${stagedir}"'
# directories is simply expanded as this reduces redundant processing and the
# directory variables are not to be modified after this point.

ifneq (${dirgpr},)

   # A directories project is used, so make project files take the directory
   # variables from there.

   directories_project := ${basename ${notdir ${dirgpr}}}
   directories += '-DDirectories_GPR="${dirgpr}"'
   directories += '-DDirectories_Project=${directories_project}'
   directories += '-DPrefix="${prefix}"'
   directories += '-DExec_Prefix="${exec_prefix}"'
   directories += '-DBindir=${directories_project}.Bindir'
   directories += '-DLibexecdir=${directories_project}.Libexecdir'
   directories += '-DIncludedir=${directories_project}.Includedir'
   directories += '-DLibdir=${directories_project}.Libdir'

else ifeq (${relocatable_package},true)

   # Make project files use directory names relative to gprdir.

   relativize = ${if ${filter ${2}%,${1}}, \
                     ${3}${1:${2}%=%}, \
                     ${call relativize,${1},${dir ${2:%/=%}},${3}../}}
   # relativize is the recursive algorithm that converts an absolute pathname
   # into a relative one.
   # Parameters:
   #    1: an absolute pathname to convert to relative
   #    2: the absolute base pathname, being shortened until it's a prefix of 1
   #    3: a growing series of "../" to lead the relative pathname with
   # If 2 is a prefix of 1, then return 3 concatenated with the part of 1 that
   # differs from 2. Otherwise delete the last element of 2, add one level of
   # "../" to 3, and repeat.
   # Within relativize all pathnames have one trailing slash so that only whole
   # directory names will match. Otherwise "/usr/lib" could match "/usr/lib64"
   # for example.

   prep = ${subst //,/,${abspath ${call mung,${1}}}/}
   # prep prepares a pathname for use as a parameter to relativize.
   #    · Protect space and percent characters from interpretation by Make.
   #    · Normalize the pathname, eliminating ".", ".." and "//".
   #    · Append a slash.
   #    · If the input was "/", then it is now "//". Change that back to "/".

   relative_to_gprdir = \
      ${or ${call unmung,${patsubst %/,%,${call relativize \
                                               ,${call prep,${1}} \
                                               ,${call prep,${gprdir}},}}},.}
   # relative_to_gprdir converts an absolute pathname into a pathname relative
   # to gprdir. What it actually does is to prepare the input to relativize and
   # fix up its output.
   #    · Prepare the input pathname with prep.
   #    · Prepare gprdir with prep.
   #    · Call relativize with the input for parameter 1, gprdir for 2, and an
   #      empty string for 3.
   #    · Strip the result of surrounding spaces and the trailing slash.
   #    · Reverse the protection of space and percent characters.
   #    · If the result is an empty string, then return "." instead.

   directories += '-DBase="${gprdir}"'
   directories += '-DPrefix="${call relative_to_gprdir,${prefix}}"'
   directories += '-DExec_Prefix="${call relative_to_gprdir,${exec_prefix}}"'
   directories += '-DBindir="${call relative_to_gprdir,${bindir}}"'
   directories += '-DLibexecdir="${call relative_to_gprdir,${libexecdir}}"'
   directories += '-DIncludedir="${call relative_to_gprdir,${includedir}}"'
   directories += '-DLibdir="${call relative_to_gprdir,${libdir}}"'

else ifeq (${relocatable_package},false)

   # Convey the directory variables unmodified to project files.

   directories += '-DPrefix="${prefix}"'
   directories += '-DExec_Prefix="${exec_prefix}"'
   directories += '-DBindir="${bindir}"'
   directories += '-DLibexecdir="${libexecdir}"'
   directories += '-DIncludedir="${includedir}"'
   directories += '-DLibdir="${libdir}"'

else
   ${error relocatable_package must be "true" or "false".}
endif

definitions = ${directories}
# definitions is recursively expanded so that the options referenced below may
# be defined in containing makefiles after the inclusion of this file.

# Convey boolean options to Gnatprep.
definitions += \
   ${foreach option,${options}, \
             ${if ${and ${filter-out environment,${origin ${option}}}, \
                        ${filter 1,${words ${${option}}}}, \
                        ${filter true false,${${option}}}}, \
                  -D${option}=${${option}}, \
                  ${error ${option} must be "true" or "false".}}}
# For each variable listed in options, check that it didn't come from the
# environment (to prevent accidents), that its value is a single word, and that
# that word is either "true" or "false". If so, append a symbol definition;
# otherwise complain and stop.

# Convey any additional symbols that the containing makefile has defined.
definitions += ${Gnatprep_definitions}

build_targets = ${addsuffix .phony_target,${build_GPRs}}
# A phony target is defined for each build project, and the job of determining
# whether the project needs rebuilding is delegated to the builder.

stage_any_GPRs = ${if ${usage_GPRs},stage_GPRs}
# The recipie for the target stage_GPRs breaks if usage_GPRs is empty, so it's
# included as a prerequisite of build only if there are some usage projects.


#
# Make rules:
#

.SECONDEXPANSION:

all: build

configure::
	@( ${foreach variable,${configuration_variables}, \
	             ${if ${or ${findstring command line, \
	                                    ${origin ${variable}}}, \
	                       ${filter true,${${variable}_is_configured}}}, \
	                  echo '${variable} = ${value ${variable}}'; \
	                  echo '${variable}_is_configured = true';}} \
	 ) > comfignat_configuration.mk
# Out of the variables listed in configuration_variables, all that were
# overridden on the command line, and all that were previously configured, are
# written to the configuration file. A variable is considered previously
# configured if there is another variable with "_is_configured" appended to its
# name and a value of "true", and such a variable is also written for each
# configured variable. It is therefore possible to delete a variable V from the
# configuration by running "make configure V_is_configured=false".

%.gpr: %.gpr.in
	"${GNATPREP}" $< $@ ${definitions}

preprocess: $${preprocessed_files}

%.gpr.phony_target: %.gpr preprocess
	${build_GPR}
# Instead of tracking dependencies between project files, this rule simply
# requires that all preprocessing is done before any project is built.

stage_GPRs: $${usage_GPRs}
	mkdir -p "${stagedir}${gprdir}"
	cp -p ${usage_GPRs} "${stagedir}${gprdir}"
.PHONY: stage_GPRs

build: $${build_targets} $${stage_any_GPRs}

${stagedir}:
	@${MAKE} build --no-print-directory
# "make install" straight out of a source package triggers a build, but if
# something has been built then "make install" doesn't rebuild anything, just
# copies the built files to their destination.

install: ${stagedir}
	mkdir -p "${DESTDIR}/"
	cp -RPf ${install_cp_flags} "${stagedir}"/* "${DESTDIR}/"
.PHONY: install

clean::
	rm -Rf ${builddir} ${preprocessed_files}

unconfigure::
	rm -f comfignat_configuration.mk

distclean: clean unconfigure