aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/buildfile
blob: 3518d932b4cc58e915c2897963d91a909be0fb39 (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
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
# file      : libbuild2/buildfile
# license   : MIT; see accompanying LICENSE file

# NOTE: remember to update bundled_modules in libbuild2/module.cxx if adding a
#       new module.
#
bundled_modules = bash/ bin/ c/ cc/ cli/ cxx/ in/ version/

./: lib{build2} $bundled_modules

# Note that we have to load these buildfiles explicitly in order to have their
# imports processed before the $config.save() call below. Failed that, we will
# get a warning about saving unused config.import.* values.
#
include $bundled_modules

# A module should treat lib{build2} as an "implied interface dependency"
# meaning that it can link it as an implementation dependency and assume that
# whomever imports and links this module will also import and link lib{build2}
# explicitly. A module should also assume that lib{butl} will always be an
# interface dependency of lib{build2} and therefore need not be explicitly
# imported or linked.

# NOTE: shared imports should go into root.build.
#
intf_libs = $libbutl

lib{build2}: libul{build2}:               \
  {hxx ixx txx cxx}{* -utility-*installed \
                      -common-options     \
                      -b-options          \
                      -config             \
                      -version            \
                      -*.test...}         \
  {hxx ixx cxx}{common-options}           \
  {hxx ixx cxx}{b-options}                \
  {hxx}{config version}

libul{build2}: script/{hxx ixx txx cxx}{** -*-options -**.test...} \
               script/{hxx ixx cxx}{builtin-options}

libul{build2}: build/script/{hxx ixx txx cxx}{** -*-options -**.test...} \
               build/script/{hxx ixx cxx}{builtin-options}

# Note that this won't work in libul{} since it's not installed.
#
lib{build2}: cxx{utility-installed}:   for_install = true
lib{build2}: cxx{utility-uninstalled}: for_install = false

# These are "core modules" that come bundled with libbuild2 (see also unit
# tests loop below). Note that the build system core can still function
# without them or with their alternative implementations. Also note that
# config/utility.?xx are part of the build system core (see comments in the
# header for details).
#
# NOTE: remember to update import_modules() in libbuild2/modules.cxx if adding
#       a new such module.
#
libul{build2}: config/{hxx ixx txx cxx}{** -host-config -**.test...} \
               config/cxx{host-config}

# Derive ~host and ~build2 configurations from current configuration.
#
# This will of course blow up spectacularly if we are cross-compiling. But
# let's wait and enjoy the fireworks (and get a sense of why someone would
# want to cross-compile a build system).
#
# For the ~host configuration we only want c/cxx/cc and bin that they load.
# For ~build2 we want to keep everything except dist.
#
# We also remove comment lines which could be confused with preprocessor
# directives by some lesser compilers and blank lines between groups of
# options which could cause spurious rebuilds when we filter out entire
# groups.
#
# For ~host also filter out config.bin.lib/config.bin.*.lib (static/shared
# library build/link preferences). In particular, we don't want to force
# config.bin.lib=shared since that will cause static libraries to link shared
# versions of their prerequisites (see mysql-client for a case where this can
# make a difference).
#
# For ~build2 also filter out config.install.chroot -- we definitely don't
# want it carried through. Also filter out variables that control tests
# execution.
#
# Finally, for both ~host and ~build2 we keep config.config.environment
# but strip config.config.hermetic* (we shouldn't be forcing hermiticity
# on the users of ~host/~build2; they can decide for themselves if they
# want it).
#
# The *_no_warnings variants are with the suppressed C/C++ compiler warnings
# (in particular, used for private host configuration in bpkg).
#
#
host_config_lines = [strings]
build2_config_lines = [strings]

host_config_no_warnings_lines = [strings]
build2_config_no_warnings_lines = [strings]

for l: $regex.replace_lines(                                                   \
  $config.save(),                                                              \
  '^( *(#|(config\.(test[. ]|dist\.|install\.chroot|config\.hermetic))).*|)$', \
  [null])
{
  # Note: also preserve config.version.
  #
  h = [null]
  if $regex.match(                                                          \
    $l,                                                                     \
    ' *config\.(c[. ]|cxx[. ]|cc[.]|bin[.]|config.environment |version ).*')
  {
    if! ($regex.match(\
           $l,        \
           ' *config\.bin\.(lib|exe\.lib|liba\.lib|libs\.lib)[ =].*'))
    {
      # Filter out sanitizer options in ~host. We run the toolchain with
      # various sanitizers on CI but sanitizers cause issues in some packages.
      # Note that we can have both -fsanitize and -fno-sanitize forms. For
      # example:
      #
      # -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all
      #
      if $regex.match($l, ' *config\.(c|cxx|cc)\.(coptions|loptions)[ =].*')
      {
        h = $regex.replace($l, ' ?-f(no-)?sanitize[=-][^ ]+', '')
      }
      else
        h = $l
    }
  }

  if ($h != [null])
    host_config_lines += $h

  build2_config_lines += $l

  # Append the warning suppressing option to config.{c,cxx}.coptions rather
  # than config.cc.coptions since the former could re-enable them.
  #
  if ($regex.match($l, ' *config\.(c|cxx)\.coptions[ =].*'))
  {
    # Note that in MSVC overriding one warning option (say /W3) with another
    # (say /w) triggers a warning. However, our compile_rule sanitizes the
    # command line to resolve such overrides (see msvc_sanitize_cl()).
    #
    o = ($cxx.class == 'gcc' ? -w : $cxx.class == 'msvc' ? /w : )

    if ($regex.match($l, '[^=]+= *\[null\] *'))
    {
      l = $regex.replace($l, '= *\[null\] *$', "= $o")
      h = $regex.replace($h, '= *\[null\] *$', "= $o")
    }
    else
    {
      l = $regex.replace($l, '=(.*)$', "=\\1 $o")
      h = $regex.replace($h, '=(.*)$', "=\\1 $o")
    }
  }

  if ($h != [null])
    host_config_no_warnings_lines += $h

  build2_config_no_warnings_lines += $l
}

config/cxx{host-config}: config/in{host-config}
{
  host_config   = $regex.merge($host_config_lines,   '(.+)', '\1\n')
  build2_config = $regex.merge($build2_config_lines, '(.+)', '\1\n')

  host_config_no_warnings   = $regex.merge($host_config_no_warnings_lines,   \
                                           '(.+)', '\1\n')
  build2_config_no_warnings = $regex.merge($build2_config_no_warnings_lines, \
                                           '(.+)', '\1\n')
}

libul{build2}: dist/{hxx ixx txx cxx}{** -**.test...}

libul{build2}: install/{hxx ixx txx cxx}{** -**.test...}

libul{build2}: test/{hxx ixx txx cxx}{** -**.test...}

libul{build2}: $intf_libs

# Include the generated config and version headers into the distribution (so
# that we don't pick up installed ones) and don't remove them when cleaning in
# src (so that clean results in a state identical to distributed).
#
hxx{config}: in{config}
hxx{version}: in{version} $src_root/manifest

hxx{config version}:
{
  dist  = true
  clean = ($src_root != $out_root)
}

# Unit tests.
#
exe{*.test}:
{
  test = true
  install = false
}

for t:         cxx{ *.test...} \
        script/cxx{**.test...} \
         build/cxx{**.test...} \
        config/cxx{**.test...} \
          dist/cxx{**.test...} \
       install/cxx{**.test...} \
          test/cxx{**.test...}
{
  d = $directory($t)
  n = $name($t)...
  b = $path.base($name($t))

  ./: $d/exe{$n}: $t $d/{hxx ixx txx}{+$n} $d/testscript{+$n +$b+*.test...}
  $d/exe{$n}: libul{build2}: bin.whole = false
  $d/exe{$n}: cxx{utility-uninstalled}
}

# Build options.
#
# NOTE: this scope happens to be outer to the bundled modules which means they
#       will inherit any scope-wide options. So we should normally only set
#       them on targets.
#
obja{*}: cxx.poptions += -DLIBBUILD2_STATIC_BUILD
objs{*}: cxx.poptions += -DLIBBUILD2_SHARED_BUILD

# Pass our compiler target to be used as build2 host and our out_root to be
# used as the build system import path (unless cross-compiling and not
# forgetting to escape backslashes on Windows).
#
{obja objs}{context}: cxx.poptions += "-DBUILD2_HOST_TRIPLET=\"$cxx.target\""

# Note that we used to compare complete target triplets but that proved too
# strict. For example, we may be running on x86_64-apple-darwin17.7.0 while
# the compiler is targeting x86_64-apple-darwin17.3.0.
#
cross = ($cxx.target.cpu != $build.host.cpu || \
         $cxx.target.system != $build.host.system)

if! $cross
{
  {obja objs}{context}: cxx.poptions += \
    -DBUILD2_IMPORT_PATH=\"$regex.replace($out_root, '\\', '\\\\')\"
}

# Note that while the -installed object file should only be linked when we
# are installing, it will be compiled even in the uninstalled case.
#
if ($install.root != [null])
{
  # Only if installed.
  #
  {obja objs}{utility-installed}: cxx.poptions += \
    -DBUILD2_INSTALL_LIB=\"$regex.replace(\
      $install.resolve($install.lib), '\\', '\\\\')\"

  # Only if configured.
  #
  # Note: strip the last directory component (<project>).
  #
  # @@ TMP drop after 0.16.0 release.
  #
  install_buildfile = ($install.buildfile != [null] \
                       ? $directory($install.resolve($install.buildfile)) \
                       :)
  {obja objs}{utility-installed utility-uninstalled}: cxx.poptions += \
    -DBUILD2_INSTALL_BUILDFILE=\"$regex.replace($install_buildfile, '\\', '\\\\')\"

  #\
  {obja objs}{utility-installed utility-uninstalled}: cxx.poptions += \
    -DBUILD2_INSTALL_BUILDFILE=\"$regex.replace(\
      $directory($install.resolve($install.buildfile)), '\\', '\\\\')\"
  #\

  # Data directory or src_root if not installed.
  #
  # Note: normalized in both cases.
  #
  {obja objs}{utility-installed}: cxx.poptions += \
    -DBUILD2_INSTALL_DATA=\"$regex.replace(\
      $install.resolve($install.data), '\\', '\\\\')\"

  {obja objs}{utility-uninstalled}: cxx.poptions += \
    -DBUILD2_INSTALL_DATA=\"$regex.replace(\
      $src_root, '\\', '\\\\')\"
}

if ($cxx.target.class != 'windows')
{
  libul{build2}: cxx.libs += -lpthread

  # Note: only linking libdl in shared build.
  #
  if ($cxx.target.class != "bsd")
    libus{build2}: cxx.libs += -ldl
}
else
{
  # @@ TMP work around Clang bug #45021.
  #
  if ($cxx.id == 'clang' && $cxx.target.system == 'win32-msvc')
  {
    if ($regex.find_match($cc.coptions $cxx.coptions, '-O[23]'))
      script/obj{run}: cxx.coptions += -O1
  }
}

# Export options.
#
lib{build2}:
{
  cxx.export.poptions = "-I$out_root" "-I$src_root"
  cxx.export.libs = $intf_libs
}

# While we don't call any pthread_*() functions in our API, this appears to be
# needed for some std::thread implementations (like libstdc++).
#
if ($cxx.target.class != 'windows')
  lib{build2}: cxx.export.libs += -lpthread

liba{build2}: cxx.export.poptions += -DLIBBUILD2_STATIC
libs{build2}: cxx.export.poptions += -DLIBBUILD2_SHARED

# For pre-releases use the complete version to make sure they cannot be used
# in place of another pre-release or the final version. See the version module
# for details on the version.* variable values.
#
if $version.pre_release
  lib{build2}: bin.lib.version = @"-$version.project_id"
else
  lib{build2}: bin.lib.version = @"-$version.major.$version.minor"

# Generated options parser.
#
# Note that the cli runtime namespace is build2::build::cli rather than
# build2::cli. That's because the cli namespace inside build2 is reserved for
# the cli build system module (libbuild2-cli). In fact, every namespace inside
# build2 is reserved for a potential module and the only namespace names we
# can use are build (this name, along with import and export, is reserved by
# the build system core) and names that start with an underscore.
#
if $cli.configured
{
  cli.options += --std c++11 -I $src_root --include-with-brackets \
--cli-namespace build2::build::cli --generate-specifier

  cli.cxx{*}:
  {
    # Include the generated cli files into the distribution and don't remove
    # them when cleaning in src (so that clean results in a state identical
    # to distributed).
    #
    dist  = true
    clean = ($src_root != $out_root)

    # We keep the generated code in the repository so copy it back to src in
    # case of a forwarded configuration.
    #
    backlink = overwrite
  }

  cli.cxx{common-options}: cli{common}
  {
    cli.options += --include-prefix libbuild2 --guard-prefix LIBBUILD2 \
--export-symbol LIBBUILD2_SYMEXPORT \
--hxx-prologue '#include <libbuild2/export.hxx>' \
--generate-file-scanner --generate-vector-scanner
  }

  cli.cxx{b-options}: cli{b}
  {
    cli.options += --include-prefix libbuild2 --guard-prefix LIBBUILD2 \
--export-symbol LIBBUILD2_SYMEXPORT \
--hxx-prologue '#include <libbuild2/export.hxx>' \
--cxx-prologue "#include <libbuild2/types-parsers.hxx>" \
--keep-separator --generate-parse --generate-merge

    # Usage options.
    #
    cli.options += --suppress-undocumented --long-usage --ansi-color \
--ascii-tree --page-usage 'build2::print_$name$_' --option-length 23
  }

  script/cli.cxx{builtin-options}: script/cli{builtin}
  {
    cli.options += --include-prefix libbuild2/script \
--guard-prefix LIBBUILD2_SCRIPT --generate-modifier --suppress-usage

    # Don't install the generated cli headers since they are only used
    # internally in the script implementation.
    #
    install = false
  }

  build/script/cli.cxx{builtin-options}: build/script/cli{builtin}
  {
    cli.options += --include-prefix libbuild2/build/script \
--guard-prefix LIBBUILD2_BUILD_SCRIPT \
--cxx-prologue "#include <libbuild2/types-parsers.hxx>" \
--generate-parse --generate-modifier --suppress-usage

    # Don't install the generated cli headers since they are only used
    # internally in the buildscript implementation.
    #
    install = false
  }
}
else
{
  # No install for the pre-generated case.
  #
  script/hxx{builtin-options}@script/ \
  script/ixx{builtin-options}@script/: install = false

  build/script/hxx{builtin-options}@build/script/ \
  build/script/ixx{builtin-options}@build/script/: install = false
}

# Install into the libbuild2/ subdirectory of, say, /usr/include/
# recreating subdirectories.
#
{hxx ixx txx}{*}:
{
  install         = include/libbuild2/
  install.subdirs = true
}