Initial module implementation
At this stage it handles Autoconf (#undef), CMake (#cmakedefine), and Meson (#mesondefine) special lines but does not have any built-in tests.
This commit is contained in:
parent
19fcde9ddc
commit
ef54e197e9
@ -8,8 +8,8 @@ CMake and Meson variants.
|
|||||||
|
|
||||||
Similar to Autoconf, the module provides built-in support for a number of
|
Similar to Autoconf, the module provides built-in support for a number of
|
||||||
common `HAVE_*` configuration options. However, the values of these options
|
common `HAVE_*` configuration options. However, the values of these options
|
||||||
are not discovered by probing, such as trying to compile a test program to
|
are not discovered by dynamic probing, such as trying to compile a test
|
||||||
check if the header is present. Instead, they are set to the expected values
|
program to check if the header is present. Instead, they are set to static
|
||||||
based on the platform/compiler macros.
|
expected values based on the platform/compiler macros.
|
||||||
|
|
||||||
[module-in]: https://build2.org/build2/doc/build2-build-system-manual.xhtml#module-in
|
[module-in]: https://build2.org/build2/doc/build2-build-system-manual.xhtml#module-in
|
||||||
|
24
libbuild2-autoconf-tests/.gitignore
vendored
Normal file
24
libbuild2-autoconf-tests/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Compiler/linker output.
|
||||||
|
#
|
||||||
|
*.d
|
||||||
|
*.t
|
||||||
|
*.i
|
||||||
|
*.i.*
|
||||||
|
*.ii
|
||||||
|
*.ii.*
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.gcm
|
||||||
|
*.pcm
|
||||||
|
*.ifc
|
||||||
|
*.so
|
||||||
|
*.dll
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
*.exp
|
||||||
|
*.pdb
|
||||||
|
*.ilk
|
||||||
|
*.exe
|
||||||
|
*.exe.dlls/
|
||||||
|
*.exe.manifest
|
||||||
|
*.pc
|
1
libbuild2-autoconf-tests/AUTHORS
Symbolic link
1
libbuild2-autoconf-tests/AUTHORS
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../AUTHORS
|
1
libbuild2-autoconf-tests/LICENSE
Symbolic link
1
libbuild2-autoconf-tests/LICENSE
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../LICENSE
|
3
libbuild2-autoconf-tests/README.md
Normal file
3
libbuild2-autoconf-tests/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# libbuild2-autoconf-tests
|
||||||
|
|
||||||
|
Tests package for the Autoconf emulation build system module for `build2`.
|
1
libbuild2-autoconf-tests/basics/buildfile
Normal file
1
libbuild2-autoconf-tests/basics/buildfile
Normal file
@ -0,0 +1 @@
|
|||||||
|
./: testscript
|
208
libbuild2-autoconf-tests/basics/testscript
Normal file
208
libbuild2-autoconf-tests/basics/testscript
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
# Note: --silent rather than --quiet to suppress module update diagnostics.
|
||||||
|
#
|
||||||
|
test.options += --no-default-options --serial-stop --silent --buildfile -
|
||||||
|
|
||||||
|
# We disable bdep auto-synchronization since we will potentially be updating
|
||||||
|
# the module from multiple parallel tests. Note that we've made sure it is
|
||||||
|
# up-to-date by pre-loading it in the tests project (see root.build for
|
||||||
|
# details).
|
||||||
|
#
|
||||||
|
+export BDEP_SYNC=0
|
||||||
|
|
||||||
|
# Note that we are using the libbuild2-autoconf-tests project as our
|
||||||
|
# amalgamation in order to get the module import location and config.c.
|
||||||
|
#
|
||||||
|
+cat <<EOI >=bootstrap.build
|
||||||
|
project = basics
|
||||||
|
#amalgamation =
|
||||||
|
subprojects =
|
||||||
|
|
||||||
|
version = 1.2.3
|
||||||
|
EOI
|
||||||
|
|
||||||
|
+cat <<EOI >=root.build
|
||||||
|
using c
|
||||||
|
using autoconf
|
||||||
|
EOI
|
||||||
|
|
||||||
|
: basics-autoconf
|
||||||
|
:
|
||||||
|
mkdir build;
|
||||||
|
ln -s ../../bootstrap.build ../../root.build build/;
|
||||||
|
cat <<EOI >=config.h.in;
|
||||||
|
#define VERSION "@version@"
|
||||||
|
|
||||||
|
#undef TRUE
|
||||||
|
#undef FALSE
|
||||||
|
#undef ONE
|
||||||
|
#undef ZERO
|
||||||
|
#undef VALUE
|
||||||
|
|
||||||
|
# undef TRUE
|
||||||
|
|
||||||
|
#undef CUSTOM_LINE
|
||||||
|
#undef CUSTOM_BLOCK
|
||||||
|
EOI
|
||||||
|
$* <<EOI &config.h &config.h.d;
|
||||||
|
./: h{config}: in{config}
|
||||||
|
{
|
||||||
|
TRUE = true
|
||||||
|
FALSE = [bool] false
|
||||||
|
ONE = 1
|
||||||
|
ZERO = [uint64] 000
|
||||||
|
VALUE = [uint64] 0123
|
||||||
|
|
||||||
|
CUSTOM_LINE = '#define CUSTOM 123'
|
||||||
|
CUSTOM_BLOCK = \
|
||||||
|
'
|
||||||
|
/* Make sure we do not redefine CUSTOM. */
|
||||||
|
#ifndef CUSTOM
|
||||||
|
# define CUSTOM 123
|
||||||
|
#endif
|
||||||
|
'
|
||||||
|
}
|
||||||
|
EOI
|
||||||
|
cat config.h >>EOO
|
||||||
|
#define VERSION "1.2.3"
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
#undef FALSE
|
||||||
|
#define ONE 1
|
||||||
|
#undef ZERO
|
||||||
|
#define VALUE 123
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
|
||||||
|
#define CUSTOM 123
|
||||||
|
/* Make sure we do not redefine CUSTOM. */
|
||||||
|
#ifndef CUSTOM
|
||||||
|
# define CUSTOM 123
|
||||||
|
#endif
|
||||||
|
EOO
|
||||||
|
|
||||||
|
: basics-cmake
|
||||||
|
:
|
||||||
|
mkdir build;
|
||||||
|
ln -s ../../bootstrap.build ../../root.build build/;
|
||||||
|
cat <<EOI >=config.h.in;
|
||||||
|
#define VERSION "@version@"
|
||||||
|
|
||||||
|
#cmakedefine TRUE
|
||||||
|
#cmakedefine FALSE
|
||||||
|
#cmakedefine ONE
|
||||||
|
#cmakedefine ZERO
|
||||||
|
#cmakedefine VALUE
|
||||||
|
|
||||||
|
# cmakedefine TRUE
|
||||||
|
|
||||||
|
#cmakedefine CUSTOM_LINE
|
||||||
|
#cmakedefine CUSTOM_BLOCK
|
||||||
|
#cmakedefine CUSTOM_BLOCK @version@
|
||||||
|
|
||||||
|
#cmakedefine TRUE true
|
||||||
|
#cmakedefine FALSE false
|
||||||
|
#cmakedefine VALUE @VALUE@ /* @version@ */
|
||||||
|
EOI
|
||||||
|
$* <<EOI &config.h &config.h.d;
|
||||||
|
./: h{config}: in{config}
|
||||||
|
{
|
||||||
|
autoconf.flavor = cmake
|
||||||
|
|
||||||
|
TRUE = true
|
||||||
|
FALSE = [bool] false
|
||||||
|
ONE = 1
|
||||||
|
ZERO = [uint64] 000
|
||||||
|
VALUE = [uint64] 0123
|
||||||
|
|
||||||
|
CUSTOM_LINE = '#define CUSTOM 123'
|
||||||
|
CUSTOM_BLOCK = \
|
||||||
|
'
|
||||||
|
/* Make sure we do not redefine CUSTOM. */
|
||||||
|
#ifndef CUSTOM
|
||||||
|
# define CUSTOM 123
|
||||||
|
#endif
|
||||||
|
'
|
||||||
|
}
|
||||||
|
EOI
|
||||||
|
cat config.h >>EOO
|
||||||
|
#define VERSION "1.2.3"
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
#undef FALSE
|
||||||
|
#define ONE 1
|
||||||
|
#undef ZERO
|
||||||
|
#define VALUE 123
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
|
||||||
|
#define CUSTOM 123
|
||||||
|
/* Make sure we do not redefine CUSTOM. */
|
||||||
|
#ifndef CUSTOM
|
||||||
|
# define CUSTOM 123
|
||||||
|
#endif
|
||||||
|
/* Make sure we do not redefine CUSTOM. */
|
||||||
|
#ifndef CUSTOM
|
||||||
|
# define CUSTOM 123
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TRUE true
|
||||||
|
#undef FALSE
|
||||||
|
#define VALUE 123 /* 1.2.3 */
|
||||||
|
EOO
|
||||||
|
|
||||||
|
: basics-meson
|
||||||
|
:
|
||||||
|
mkdir build;
|
||||||
|
ln -s ../../bootstrap.build ../../root.build build/;
|
||||||
|
cat <<EOI >=config.h.in;
|
||||||
|
#define VERSION "@version@"
|
||||||
|
|
||||||
|
#mesondefine TRUE
|
||||||
|
#mesondefine FALSE
|
||||||
|
#mesondefine ONE
|
||||||
|
#mesondefine ZERO
|
||||||
|
#mesondefine VALUE
|
||||||
|
|
||||||
|
# mesondefine TRUE
|
||||||
|
|
||||||
|
#mesondefine CUSTOM_LINE
|
||||||
|
#mesondefine CUSTOM_BLOCK
|
||||||
|
EOI
|
||||||
|
$* <<EOI &config.h &config.h.d;
|
||||||
|
./: h{config}: in{config}
|
||||||
|
{
|
||||||
|
autoconf.flavor = meson
|
||||||
|
|
||||||
|
TRUE = true
|
||||||
|
FALSE = [bool] false
|
||||||
|
ONE = 1
|
||||||
|
ZERO = [uint64] 000
|
||||||
|
VALUE = [uint64] 0123
|
||||||
|
|
||||||
|
CUSTOM_LINE = '#define CUSTOM 123'
|
||||||
|
CUSTOM_BLOCK = \
|
||||||
|
'
|
||||||
|
/* Make sure we do not redefine CUSTOM. */
|
||||||
|
#ifndef CUSTOM
|
||||||
|
# define CUSTOM 123
|
||||||
|
#endif
|
||||||
|
'
|
||||||
|
}
|
||||||
|
EOI
|
||||||
|
cat config.h >>EOO
|
||||||
|
#define VERSION "1.2.3"
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
#undef FALSE
|
||||||
|
#define ONE 1
|
||||||
|
#undef ZERO
|
||||||
|
#define VALUE 123
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
|
||||||
|
#define CUSTOM 123
|
||||||
|
/* Make sure we do not redefine CUSTOM. */
|
||||||
|
#ifndef CUSTOM
|
||||||
|
# define CUSTOM 123
|
||||||
|
#endif
|
||||||
|
EOO
|
4
libbuild2-autoconf-tests/build/.gitignore
vendored
Normal file
4
libbuild2-autoconf-tests/build/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/config.build
|
||||||
|
/root/
|
||||||
|
/bootstrap/
|
||||||
|
build/
|
6
libbuild2-autoconf-tests/build/bootstrap.build
Normal file
6
libbuild2-autoconf-tests/build/bootstrap.build
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
project = libbuild2-autoconf-tests
|
||||||
|
|
||||||
|
using version
|
||||||
|
using config
|
||||||
|
using test
|
||||||
|
using dist
|
12
libbuild2-autoconf-tests/build/root.build
Normal file
12
libbuild2-autoconf-tests/build/root.build
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Load the module to make sure it is up-to-date before we start running the
|
||||||
|
# tests. Failed that, we may try to update it from multiple tests in parallel.
|
||||||
|
# Also, our tests use this project as their amalgamation in order to get the
|
||||||
|
# module import location (as well as the C module configuration).
|
||||||
|
#
|
||||||
|
using autoconf
|
||||||
|
|
||||||
|
using c
|
||||||
|
|
||||||
|
# @@ Should we be able to do just test = $build.path?
|
||||||
|
#
|
||||||
|
testscript{*}: test = $recall($build.path)
|
1
libbuild2-autoconf-tests/buildfile
Normal file
1
libbuild2-autoconf-tests/buildfile
Normal file
@ -0,0 +1 @@
|
|||||||
|
./: {*/ -build/} doc{README.md} legal{LICENSE AUTHORS} manifest
|
11
libbuild2-autoconf-tests/manifest
Normal file
11
libbuild2-autoconf-tests/manifest
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
: 1
|
||||||
|
name: libbuild2-autoconf-tests
|
||||||
|
version: 0.1.0-a.0.z
|
||||||
|
project: build2
|
||||||
|
summary: Tests for the Autoconf emulation build system module for build2
|
||||||
|
license: MIT ; MIT License.
|
||||||
|
description-file: README.md
|
||||||
|
url: https://github.com/build2/libbuild2-autoconf
|
||||||
|
email: users@build2.org
|
||||||
|
depends: * build2 >= 0.15.0-
|
||||||
|
depends: * bpkg >= 0.15.0-
|
24
libbuild2-autoconf/.gitignore
vendored
Normal file
24
libbuild2-autoconf/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Compiler/linker output.
|
||||||
|
#
|
||||||
|
*.d
|
||||||
|
*.t
|
||||||
|
*.i
|
||||||
|
*.i.*
|
||||||
|
*.ii
|
||||||
|
*.ii.*
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.gcm
|
||||||
|
*.pcm
|
||||||
|
*.ifc
|
||||||
|
*.so
|
||||||
|
*.dll
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
*.exp
|
||||||
|
*.pdb
|
||||||
|
*.ilk
|
||||||
|
*.exe
|
||||||
|
*.exe.dlls/
|
||||||
|
*.exe.manifest
|
||||||
|
*.pc
|
1
libbuild2-autoconf/AUTHORS
Symbolic link
1
libbuild2-autoconf/AUTHORS
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../AUTHORS
|
1
libbuild2-autoconf/LICENSE
Symbolic link
1
libbuild2-autoconf/LICENSE
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../LICENSE
|
1
libbuild2-autoconf/README.md
Symbolic link
1
libbuild2-autoconf/README.md
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../README.md
|
4
libbuild2-autoconf/build/.gitignore
vendored
Normal file
4
libbuild2-autoconf/build/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/config.build
|
||||||
|
/root/
|
||||||
|
/bootstrap/
|
||||||
|
build/
|
7
libbuild2-autoconf/build/bootstrap.build
Normal file
7
libbuild2-autoconf/build/bootstrap.build
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
project = libbuild2-autoconf
|
||||||
|
|
||||||
|
using version
|
||||||
|
using config
|
||||||
|
using test
|
||||||
|
using install
|
||||||
|
using dist
|
6
libbuild2-autoconf/build/export.build
Normal file
6
libbuild2-autoconf/build/export.build
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
$out_root/
|
||||||
|
{
|
||||||
|
include libbuild2/autoconf/
|
||||||
|
}
|
||||||
|
|
||||||
|
export $out_root/libbuild2/autoconf/$import.target
|
16
libbuild2-autoconf/build/root.build
Normal file
16
libbuild2-autoconf/build/root.build
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
cxx.std = latest
|
||||||
|
|
||||||
|
using cxx
|
||||||
|
|
||||||
|
hxx{*}: extension = hxx
|
||||||
|
ixx{*}: extension = ixx
|
||||||
|
txx{*}: extension = txx
|
||||||
|
cxx{*}: extension = cxx
|
||||||
|
|
||||||
|
if ($cxx.target.system == 'win32-msvc')
|
||||||
|
cc.poptions += -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS
|
||||||
|
|
||||||
|
if ($cxx.class == 'msvc')
|
||||||
|
cc.coptions += /wd4251 /wd4275 /wd4800
|
||||||
|
elif ($cxx.id == 'gcc')
|
||||||
|
cxx.coptions += -Wno-maybe-uninitialized -Wno-free-nonheap-object # libbutl
|
1
libbuild2-autoconf/buildfile
Normal file
1
libbuild2-autoconf/buildfile
Normal file
@ -0,0 +1 @@
|
|||||||
|
./: {*/ -build/} doc{README.md} legal{LICENSE AUTHORS} manifest
|
3
libbuild2-autoconf/libbuild2/autoconf/.gitignore
vendored
Normal file
3
libbuild2-autoconf/libbuild2/autoconf/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Generated version header.
|
||||||
|
#
|
||||||
|
version.hxx
|
47
libbuild2-autoconf/libbuild2/autoconf/buildfile
Normal file
47
libbuild2-autoconf/libbuild2/autoconf/buildfile
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
intf_libs = # Interface dependencies.
|
||||||
|
impl_libs = # Implementation dependencies.
|
||||||
|
|
||||||
|
import impl_libs += build2%lib{build2} # Implied interface dependency.
|
||||||
|
import impl_libs += build2%lib{build2-in}
|
||||||
|
|
||||||
|
lib{build2-autoconf}: {hxx ixx txx cxx}{**} $impl_libs $intf_libs
|
||||||
|
|
||||||
|
# Build options.
|
||||||
|
#
|
||||||
|
cxx.poptions =+ "-I$out_root" "-I$src_root"
|
||||||
|
|
||||||
|
obja{*}: cxx.poptions += -DLIBBUILD2_AUTOCONF_STATIC_BUILD
|
||||||
|
objs{*}: cxx.poptions += -DLIBBUILD2_AUTOCONF_SHARED_BUILD
|
||||||
|
|
||||||
|
# Export options.
|
||||||
|
#
|
||||||
|
lib{build2-autoconf}:
|
||||||
|
{
|
||||||
|
cxx.export.poptions = "-I$out_root" "-I$src_root"
|
||||||
|
cxx.export.libs = $intf_libs
|
||||||
|
}
|
||||||
|
|
||||||
|
liba{build2-autoconf}: cxx.export.poptions += -DLIBBUILD2_AUTOCONF_STATIC
|
||||||
|
libs{build2-autoconf}: cxx.export.poptions += -DLIBBUILD2_AUTOCONF_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-autoconf}: bin.lib.version = "-$version.project_id"
|
||||||
|
else
|
||||||
|
lib{build2-autoconf}: bin.lib.version = "-$version.major.$version.minor"
|
||||||
|
|
||||||
|
# Embed the build system core version as our load suffix.
|
||||||
|
#
|
||||||
|
libs{build2-autoconf}: bin.lib.load_suffix = "-$build.version.interface"
|
||||||
|
|
||||||
|
# Install into the libbuild2/autoconf/ subdirectory of, say, /usr/include/
|
||||||
|
# recreating subdirectories.
|
||||||
|
#
|
||||||
|
{hxx ixx txx}{*}:
|
||||||
|
{
|
||||||
|
install = include/libbuild2/autoconf/
|
||||||
|
install.subdirs = true
|
||||||
|
}
|
38
libbuild2-autoconf/libbuild2/autoconf/export.hxx
Normal file
38
libbuild2-autoconf/libbuild2/autoconf/export.hxx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Normally we don't export class templates (but do complete specializations),
|
||||||
|
// inline functions, and classes with only inline member functions. Exporting
|
||||||
|
// classes that inherit from non-exported/imported bases (e.g., std::string)
|
||||||
|
// will end up badly. The only known workarounds are to not inherit or to not
|
||||||
|
// export. Also, MinGW GCC doesn't like seeing non-exported functions being
|
||||||
|
// used before their inline definition. The workaround is to reorder code. In
|
||||||
|
// the end it's all trial and error.
|
||||||
|
|
||||||
|
#if defined(LIBBUILD2_AUTOCONF_STATIC) // Using static.
|
||||||
|
# define LIBBUILD2_AUTOCONF_SYMEXPORT
|
||||||
|
#elif defined(LIBBUILD2_AUTOCONF_STATIC_BUILD) // Building static.
|
||||||
|
# define LIBBUILD2_AUTOCONF_SYMEXPORT
|
||||||
|
#elif defined(LIBBUILD2_AUTOCONF_SHARED) // Using shared.
|
||||||
|
# ifdef _WIN32
|
||||||
|
# define LIBBUILD2_AUTOCONF_SYMEXPORT __declspec(dllimport)
|
||||||
|
# else
|
||||||
|
# define LIBBUILD2_AUTOCONF_SYMEXPORT
|
||||||
|
# endif
|
||||||
|
#elif defined(LIBBUILD2_AUTOCONF_SHARED_BUILD) // Building shared.
|
||||||
|
# ifdef _WIN32
|
||||||
|
# define LIBBUILD2_AUTOCONF_SYMEXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define LIBBUILD2_AUTOCONF_SYMEXPORT
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
// If none of the above macros are defined, then we assume we are being used
|
||||||
|
// by some third-party build system that cannot/doesn't signal the library
|
||||||
|
// type. Note that this fallback works for both static and shared libraries
|
||||||
|
// provided the library only exports functions (in other words, no global
|
||||||
|
// exported data) and for the shared case the result will be sub-optimal
|
||||||
|
// compared to having dllimport. If, however, your library does export data,
|
||||||
|
// then you will probably want to replace the fallback with the (commented
|
||||||
|
// out) error since it won't work for the shared case.
|
||||||
|
//
|
||||||
|
# define LIBBUILD2_AUTOCONF_SYMEXPORT // Using static or shared.
|
||||||
|
#endif
|
75
libbuild2-autoconf/libbuild2/autoconf/init.cxx
Normal file
75
libbuild2-autoconf/libbuild2/autoconf/init.cxx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include <libbuild2/autoconf/init.hxx>
|
||||||
|
|
||||||
|
#include <libbuild2/scope.hxx>
|
||||||
|
#include <libbuild2/variable.hxx>
|
||||||
|
#include <libbuild2/diagnostics.hxx>
|
||||||
|
|
||||||
|
#include <libbuild2/autoconf/rule.hxx>
|
||||||
|
|
||||||
|
namespace build2
|
||||||
|
{
|
||||||
|
namespace autoconf
|
||||||
|
{
|
||||||
|
static const rule rule_;
|
||||||
|
|
||||||
|
//-
|
||||||
|
// The `autoconf` module.
|
||||||
|
//-
|
||||||
|
bool
|
||||||
|
init (scope& rs,
|
||||||
|
scope& bs,
|
||||||
|
const location& l,
|
||||||
|
bool,
|
||||||
|
bool,
|
||||||
|
module_init_extra&)
|
||||||
|
{
|
||||||
|
tracer trace ("autoconf::init");
|
||||||
|
l5 ([&]{trace << "for " << bs;});
|
||||||
|
|
||||||
|
// Load in.base (in.* variables, in{} target type).
|
||||||
|
//
|
||||||
|
load_module (rs, rs, "in.base", l);
|
||||||
|
|
||||||
|
// Enter variables.
|
||||||
|
//
|
||||||
|
{
|
||||||
|
auto& vp (rs.var_pool ());
|
||||||
|
|
||||||
|
// Configuration file flavor. Valid values are `autoconf` (default),
|
||||||
|
// `cmake`, and `meson`.
|
||||||
|
//
|
||||||
|
vp.insert<string> ("autoconf.flavor");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the rule.
|
||||||
|
//
|
||||||
|
// @@ TODO: this will be ambiguous, for example, version.in rule. Note
|
||||||
|
// also that if we register it for cc{}, then it will always take
|
||||||
|
// precedence over version.in, which is probably something we don't
|
||||||
|
// want. In fact, we would have liked it to be of lower precedence
|
||||||
|
// since version.in will only match if there is dependency on
|
||||||
|
// manifest.
|
||||||
|
//
|
||||||
|
rs.insert_rule<file> (perform_update_id, "autoconf.in", rule_);
|
||||||
|
rs.insert_rule<file> (perform_clean_id, "autoconf.in", rule_);
|
||||||
|
rs.insert_rule<file> (configure_update_id, "autoconf.in", rule_);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const module_functions mod_functions[] =
|
||||||
|
{
|
||||||
|
// NOTE: don't forget to also update the documentation in init.hxx if
|
||||||
|
// changing anything here.
|
||||||
|
|
||||||
|
{"autoconf", nullptr, init},
|
||||||
|
{nullptr, nullptr, nullptr}
|
||||||
|
};
|
||||||
|
|
||||||
|
const module_functions*
|
||||||
|
build2_autoconf_load ()
|
||||||
|
{
|
||||||
|
return mod_functions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
libbuild2-autoconf/libbuild2/autoconf/init.hxx
Normal file
20
libbuild2-autoconf/libbuild2/autoconf/init.hxx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libbuild2/types.hxx>
|
||||||
|
#include <libbuild2/utility.hxx>
|
||||||
|
|
||||||
|
#include <libbuild2/module.hxx>
|
||||||
|
|
||||||
|
#include <libbuild2/autoconf/export.hxx>
|
||||||
|
|
||||||
|
namespace build2
|
||||||
|
{
|
||||||
|
namespace autoconf
|
||||||
|
{
|
||||||
|
//-
|
||||||
|
// Module `autoconf` does not require bootstrapping.
|
||||||
|
//-
|
||||||
|
extern "C" LIBBUILD2_AUTOCONF_SYMEXPORT const module_functions*
|
||||||
|
build2_autoconf_load ();
|
||||||
|
}
|
||||||
|
}
|
355
libbuild2-autoconf/libbuild2/autoconf/rule.cxx
Normal file
355
libbuild2-autoconf/libbuild2/autoconf/rule.cxx
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
#include <libbuild2/autoconf/rule.hxx>
|
||||||
|
|
||||||
|
#include <libbuild2/target.hxx>
|
||||||
|
#include <libbuild2/algorithm.hxx>
|
||||||
|
#include <libbuild2/diagnostics.hxx>
|
||||||
|
|
||||||
|
namespace build2
|
||||||
|
{
|
||||||
|
namespace autoconf
|
||||||
|
{
|
||||||
|
enum class flavor {autoconf, cmake, meson};
|
||||||
|
|
||||||
|
struct match_data
|
||||||
|
{
|
||||||
|
autoconf::flavor flavor;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert (sizeof (match_data) <= target::data_size,
|
||||||
|
"insufficient space");
|
||||||
|
|
||||||
|
rule::
|
||||||
|
rule ()
|
||||||
|
: in::rule ("autoconf.in 1",
|
||||||
|
"autoconf.in",
|
||||||
|
'@' /* symbol */,
|
||||||
|
false /* strict */)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
recipe rule::
|
||||||
|
apply (action a, target& t) const
|
||||||
|
{
|
||||||
|
// Determine and cache the configuration file flavor.
|
||||||
|
//
|
||||||
|
flavor f (flavor::autoconf);
|
||||||
|
if (const string* s = cast_null<string> (t["autoconf.flavor"]))
|
||||||
|
{
|
||||||
|
if (*s == "cmake")
|
||||||
|
f = flavor::cmake;
|
||||||
|
else if (*s == "meson")
|
||||||
|
f = flavor::meson;
|
||||||
|
else if (*s != "autoconf")
|
||||||
|
fail << "invalid configuration file flavor '" << *s << "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
t.data (match_data {f});
|
||||||
|
|
||||||
|
return in::rule::apply (a, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rule::
|
||||||
|
process (const location& l,
|
||||||
|
action a, const target& t,
|
||||||
|
depdb& dd, size_t dd_skip,
|
||||||
|
string& s, size_t b,
|
||||||
|
const char* nl,
|
||||||
|
char sym,
|
||||||
|
bool strict,
|
||||||
|
const optional<string>& null) const
|
||||||
|
{
|
||||||
|
auto ws = [] (char c)
|
||||||
|
{
|
||||||
|
return c == ' ' || c == '\t';
|
||||||
|
};
|
||||||
|
|
||||||
|
auto skip_ws = [&ws] (const string& s, size_t& b)
|
||||||
|
{
|
||||||
|
for (; ws (s[b]); ++b) ;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Scan a C identifier returning its size. Return 0 if it's not a valid
|
||||||
|
// identifier or is followed by a non-whitespace.
|
||||||
|
//
|
||||||
|
auto read_id = [&ws] (const string& s, size_t b) -> size_t
|
||||||
|
{
|
||||||
|
size_t i (b);
|
||||||
|
char c;
|
||||||
|
for (; (c = s[i]) == '_' || (i == b ? alpha (c) : alnum (c)); ++i) ;
|
||||||
|
|
||||||
|
return i != b && (c == '\0' || ws (c)) ? i - b : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t i (b);
|
||||||
|
|
||||||
|
flavor f (t.data<match_data> ().flavor);
|
||||||
|
|
||||||
|
// Substitute special #undef/#cmakedfine/#mesondefine line. If value is
|
||||||
|
// false, then do not append the value to #define.
|
||||||
|
//
|
||||||
|
// Return true if it was substituted with #define, false if with #undef,
|
||||||
|
// and nullopt if with a custom block of preprocessor directives.
|
||||||
|
//
|
||||||
|
auto substitute_special = [&skip_ws, this,
|
||||||
|
&l,
|
||||||
|
a, &t,
|
||||||
|
&dd, &dd_skip,
|
||||||
|
nl, strict, &null,
|
||||||
|
&s] (const string& name,
|
||||||
|
bool value = true) -> optional<bool>
|
||||||
|
{
|
||||||
|
// Note that we must be careful here with going too ad hoc since there
|
||||||
|
// is a parallel debdb validation logic in in::rule which calls
|
||||||
|
// substitute().
|
||||||
|
//
|
||||||
|
optional<string> ov (
|
||||||
|
substitute (l, a, t, dd, dd_skip, name, strict, null));
|
||||||
|
|
||||||
|
assert (ov); // C identifier is a valid variable name.
|
||||||
|
string& v (*ov);
|
||||||
|
|
||||||
|
// As an extension, we allow replacing the entire line with a
|
||||||
|
// potentially multi-line block of preprocessor directives. To detect
|
||||||
|
// this, we look for a line that starts with `#` after whitespaces.
|
||||||
|
//
|
||||||
|
size_t p (0);
|
||||||
|
for (;; ++p)
|
||||||
|
{
|
||||||
|
skip_ws (v, p);
|
||||||
|
|
||||||
|
if (v[p] == '#')
|
||||||
|
break;
|
||||||
|
|
||||||
|
p = v.find ('\n', p);
|
||||||
|
|
||||||
|
if (p == string::npos)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<bool> r;
|
||||||
|
if (p != string::npos)
|
||||||
|
{
|
||||||
|
s.clear ();
|
||||||
|
|
||||||
|
// Skip leading and trailing newlines.
|
||||||
|
//
|
||||||
|
for (; v.back () == '\n'; v.pop_back ()) ;
|
||||||
|
for (p = 0; v[p] == '\n'; ++p) ;
|
||||||
|
|
||||||
|
for (;; ++p)
|
||||||
|
{
|
||||||
|
size_t b (p);
|
||||||
|
p = v.find ('\n', p);
|
||||||
|
|
||||||
|
s.append (v, b, p - b);
|
||||||
|
|
||||||
|
if (p == string::npos)
|
||||||
|
break;
|
||||||
|
|
||||||
|
s.append (nl); // Last line is added by our caller.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Otherwise translate false/0 to #undef and true to 1.
|
||||||
|
//
|
||||||
|
else if (v == "false" || v == "0")
|
||||||
|
{
|
||||||
|
s = "#undef ";
|
||||||
|
s += name;
|
||||||
|
r = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (v == "true")
|
||||||
|
v = "1";
|
||||||
|
|
||||||
|
s = "#define ";
|
||||||
|
s += name;
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
s += ' ';
|
||||||
|
s += v;
|
||||||
|
}
|
||||||
|
r = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Deal with special lines of each flavor. Return if the line has has
|
||||||
|
// been handled and fall through to use the normal substitution logic.
|
||||||
|
//
|
||||||
|
switch (f)
|
||||||
|
{
|
||||||
|
case flavor::autoconf:
|
||||||
|
{
|
||||||
|
// Autoconf recognizes two forms of special lines:
|
||||||
|
//
|
||||||
|
// #undef NAME
|
||||||
|
// #define NAME 0
|
||||||
|
//
|
||||||
|
// However, the latter form as well as comments after NAME in the
|
||||||
|
// former form are "strongly discouraged". So for now we only
|
||||||
|
// recognize #undef, especially seeing that it's the dominant form
|
||||||
|
// in the wild.
|
||||||
|
//
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
if (s[i] == '#')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
if (s.compare (i, 5, "undef") == 0 && ws (s[i + 5]))
|
||||||
|
{
|
||||||
|
i += 5;
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
size_t n (read_id (s, i));
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
fail (l) << "expected identifier after #undef";
|
||||||
|
|
||||||
|
string name (s, i, n);
|
||||||
|
|
||||||
|
i += n;
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
// Let's not bother with detecting comments seeing that it's
|
||||||
|
// strongly discouraged.
|
||||||
|
//
|
||||||
|
if (s[i] != '\0')
|
||||||
|
fail (l) << "junk after identifier " << name;
|
||||||
|
|
||||||
|
substitute_special (name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case flavor::cmake:
|
||||||
|
{
|
||||||
|
// CMake recognizes two forms of special lines:
|
||||||
|
//
|
||||||
|
// #cmakedefine NAME [VALUE]
|
||||||
|
// #cmakedefine01 NAME
|
||||||
|
//
|
||||||
|
// The first variant is replaced with #define if NAME is "set to any
|
||||||
|
// value not considered false" and to (commented out) #undef
|
||||||
|
// otherwise. In the former case, if VALUE is present, then it is
|
||||||
|
// processed normally with @-substitutions. So in a sense there are
|
||||||
|
// two entities at play: variable NAME controls #define/#undef while
|
||||||
|
// VALUE -- the value in case of #define. The following patterns are
|
||||||
|
// fairly common:
|
||||||
|
//
|
||||||
|
// #cmakedefine HAVE_MEMORY_H
|
||||||
|
// #cmakedefine HAVE_MEMORY_H 1
|
||||||
|
// #cmakedefine SIZEOF_LONG @SIZEOF_LONG@
|
||||||
|
//
|
||||||
|
// But also:
|
||||||
|
//
|
||||||
|
// #cmakedefine const
|
||||||
|
// #cmakedefine const @HAVE_CONST@
|
||||||
|
// #cmakedefine size_t @SIZE_T@
|
||||||
|
//
|
||||||
|
// The #cmakedefine01 variant is always replaced with #define,
|
||||||
|
// either with value 1 if NAME is true and 0 otherwise. It's doesn't
|
||||||
|
// appear to be used much in practice so we are not going to bother
|
||||||
|
// with it.
|
||||||
|
//
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
if (s[i] == '#')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
if (s.compare (i, 11, "cmakedefine") == 0 && ws (s[i + 11]))
|
||||||
|
{
|
||||||
|
i += 11;
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
size_t n (read_id (s, i));
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
fail (l) << "expected identifier after #cmakedefine";
|
||||||
|
|
||||||
|
string name (s, i, n);
|
||||||
|
|
||||||
|
i += n;
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
// If there is value, then save it for later (see below).
|
||||||
|
//
|
||||||
|
optional<string> value;
|
||||||
|
if (s[i] != '\0')
|
||||||
|
value = string (s, i);
|
||||||
|
|
||||||
|
optional<bool> r (substitute_special (name, !value));
|
||||||
|
|
||||||
|
if (!value || !r || !*r)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Append the value and fall through to the normal substitution
|
||||||
|
// logic.
|
||||||
|
//
|
||||||
|
s += ' ';
|
||||||
|
b = s.size (); // Start substituting from here.
|
||||||
|
s += *value;
|
||||||
|
}
|
||||||
|
else if (s.compare (i, 13, "cmakedefine01") == 0 && ws (s[i + 13]))
|
||||||
|
fail(l) << "#cmakedefine01 is not yet supported";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case flavor::meson:
|
||||||
|
{
|
||||||
|
// Meson recognizes only one special form:
|
||||||
|
//
|
||||||
|
// #mesondefine NAME
|
||||||
|
//
|
||||||
|
// It is replaced with commented out #undef if NAME is not set, with
|
||||||
|
// #undef if NAME is set to boolean false, with #define without a
|
||||||
|
// value if it is set to boolean true, and to #define with the value
|
||||||
|
// of NAME if it is set to integer or string.
|
||||||
|
//
|
||||||
|
// Since we don't do commented out #undef, we will treat the first
|
||||||
|
// two cases the same. We will also map the third case to value 1,
|
||||||
|
// similar to Autoconf.
|
||||||
|
//
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
if (s[i] == '#')
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
if (s.compare (i, 11, "mesondefine") == 0 && ws (s[i + 11]))
|
||||||
|
{
|
||||||
|
i += 11;
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
size_t n (read_id (s, i));
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
fail (l) << "expected identifier after #mesondefine";
|
||||||
|
|
||||||
|
string name (s, i, n);
|
||||||
|
|
||||||
|
i += n;
|
||||||
|
skip_ws (s, i);
|
||||||
|
|
||||||
|
if (s[i] != '\0')
|
||||||
|
fail (l) << "junk after identifier " << name;
|
||||||
|
|
||||||
|
substitute_special (name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
in::rule::process (l, a, t, dd, dd_skip, s, b, nl, sym, strict, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
libbuild2-autoconf/libbuild2/autoconf/rule.hxx
Normal file
38
libbuild2-autoconf/libbuild2/autoconf/rule.hxx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libbuild2/types.hxx>
|
||||||
|
#include <libbuild2/utility.hxx>
|
||||||
|
|
||||||
|
#include <libbuild2/in/rule.hxx>
|
||||||
|
|
||||||
|
namespace build2
|
||||||
|
{
|
||||||
|
namespace autoconf
|
||||||
|
{
|
||||||
|
// Process a config.h.in file.
|
||||||
|
//
|
||||||
|
// Note that to be usable as a drop-in replacement we make the default
|
||||||
|
// substitution symbol '@' and the mode -- lax. The user, however, is
|
||||||
|
// still able to override both of these choices with the corresponding
|
||||||
|
// in.* variables.
|
||||||
|
//
|
||||||
|
class rule: public in::rule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
rule ();
|
||||||
|
|
||||||
|
virtual recipe
|
||||||
|
apply (action, target&) const override;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
process (const location&,
|
||||||
|
action, const target&,
|
||||||
|
depdb&, size_t,
|
||||||
|
string&, size_t,
|
||||||
|
const char*,
|
||||||
|
char,
|
||||||
|
bool,
|
||||||
|
const optional<string>&) const override;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
13
libbuild2-autoconf/manifest
Normal file
13
libbuild2-autoconf/manifest
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
: 1
|
||||||
|
name: libbuild2-autoconf
|
||||||
|
version: 0.1.0-a.0.z
|
||||||
|
project: build2
|
||||||
|
summary: Autoconf emulation build system module for build2
|
||||||
|
license: MIT ; MIT License.
|
||||||
|
description-file: README.md
|
||||||
|
url: https://github.com/build2/libbuild2-autoconf
|
||||||
|
email: users@build2.org
|
||||||
|
build-warning-email: builds@build2.org
|
||||||
|
depends: * build2 >= 0.15.0-
|
||||||
|
depends: * bpkg >= 0.15.0-
|
||||||
|
tests: * libbuild2-autoconf-tests == $
|
4
packages.manifest
Normal file
4
packages.manifest
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
: 1
|
||||||
|
location: libbuild2-autoconf/
|
||||||
|
:
|
||||||
|
location: libbuild2-autoconf-tests/
|
Loading…
Reference in New Issue
Block a user