-
Izzard, Robert Dr (Maths & Physics) authoredIzzard, Robert Dr (Maths & Physics) authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
meson.build 19.22 KiB
############################################################
# meson build file for binary_c
#
# (c) Robert Izzard 10/11/2019
#
# Known to work with binary_c 2.1.4 using gcc and clang.
#
############################################################
############################################################
# TODO:
#
# 'gprof'/'gcov' builds
# profile-guided optimization
# build data_objects in builddir, not in source tree
# update binary_grid2 to handle install in prefix
# (perhaps? we really want these to be persistent...)
#
############################################################
#
# See also
# https://github.com/mesonbuild/meson/blob/master/docs/markdown/howtox.md
# as a useful cookbook.
#
############################################################
#
# A typical clean build with gcc and "time make" (without ccache) gives
#
# 82.20user 19.66system 0:30.18elapsed 337%CPU (0avgtext+0avgdata 330368maxresident)k
#
# While with ninja (no ccache) we get
# 55.83user 15.86system 0:20.14elapsed 355%CPU (0avgtext+0avgdata 327448maxresident)k
############################################################
# define the binary_c project
project(
'binary_c','c',
version : run_command('sh','-c','meson/binary_c_version.sh').stdout().strip(),
default_options : [
'c_std=gnu99',
]
)
binary_c_version = run_command('sh','-c','meson/binary_c_version.sh').stdout().strip()
compiler = meson.get_compiler('c')
############################################################
# System information
cpufreq = run_command('meson/cpu_frequency.sh').stdout().strip()
############################################################
# get home directory
homedir = run_command('sh','-c','echo $HOME').stdout().strip()
############################################################
# get binary_c root and src locations
binary_c = meson.source_root()
binary_c_src = meson.source_root() + '/src'
############################################################
# SVN and git information
git_revision = run_command('sh','-c','meson/git_revision.sh').stdout().strip()
svn_revision = run_command('sh','-c','meson/svn_revision.sh').stdout().strip()
git_url = run_command('sh','-c','meson/git_url.sh').stdout().strip()
svn_url = run_command('sh','-c','meson/svn_url.sh').stdout().strip()
############################################################
# default include and library search directories
incdirs = [ '.', './src' ]
libdirs = [ './src' ]
absolute_incdirs = [ binary_c, binary_c_src ]
absolute_libdirs = [ ]
############################################################
# default C flags
#
cflags = [
'-DALIGNSIZE=16'
]
############################################################
# cflags required for generic builds and other builds
#
_other_cflags = [
'-std=gnu99', # required for PCH (and cannot hurt if specified twice)
]
foreach cflag : _other_cflags
if compiler.has_argument(cflag)
cflags += [ cflag ]
endif
endforeach
############################################################
# C flags that are non-generic, i.e. machine-specific.
#
if get_option('generic') == false
_non_generic_cflags = [
# put list here
]
foreach cflag : _non_generic_cflags
__cflag = '-m' + cflag
if compiler.has_argument( __cflag )
cflags += [ __cflag ]
endif
endforeach
endif
############################################################
# optional C flags
optional_flags = [ ]
# generic build
if get_option('generic') == true
optional_flags += [
'-mtune=generic',
]
else
optional_flags += [
'-march=native',
'-mtune=native',
]
endif
# accurate mathematical options
if get_option('accurate') == true
optional_flags += [
'-frounding-math',
'-fno-stack-protector',
'-ffloat-store',
'-fno-fast-math'
]
else
optional_flags += [
'-ffast-math',
'-fno-associative-math',
]
endif
optional_flags += [
'-fno-finite-math-only',
'-fsignaling-nans',
'-fomit-frame-pointer',
'-fvisibility=hidden',
]
############################################################
# debug C flags
if get_option('buildtype').startswith('debug')
optional_flags += [ '-rdynamic', '-O0' ]
endif
############################################################
# Now go through the optional_flags, and use those that
# are supported by the compiler.
#
foreach _flag : optional_flags
if compiler.has_argument(_flag)
cflags += _flag
endif
endforeach
############################################################
# per-compiler options
#
if compiler.get_id() == 'clang'
# clang-speific flags
cflags += [ '-fbracket-depth=512' ]
else
# gcc-specific flags
cflags += []
endif
############################################################
# system options
#
cflags += '-DCPUFREQ=' + cpufreq
############################################################
# operating system flags
#
os = host_machine.system()
cflags += [
'-DOPERATING_SYSTEM=' + os
]
if os == 'linux'
# Linux system
cflags += [
'-DLINUX',
'-DLARGEFILE_SOURCE'
]
elif os == 'windows'
# windows
cflags += [
'-DWINDOWS'
]
elif os == 'darwin'
# darwin (MacOSX)
cflags += [
'-DDARWIN'
]
else
cflags += [
'-DUNKNOWN_OPERATING_SYSTEM'
]
endif
############################################################
# 64- or 32-bit build
#
if compiler.compiles('int main(int argc,char **argv){return 0;}',
args : '-m64',
name : '64-bit check')
# 64-bit system
cflags += '-D_FILE_OFFSET_BITS=64'
else
# assume 32-bit system
endif
############################################################
# version control options
if git_revision != ''
_flag = '-DGIT_REVISION="' + git_revision + '"'
cflags += _flag
endif
if svn_revision != ''
_flag = '-DSVN_REVISION="' + svn_revision + '"'
cflags += _flag
endif
if git_url != ''
_flag = '-DGIT_URL="' + git_url + '"'
cflags += _flag
endif
if svn_url != ''
_flag = '-DSVN_URL="' + svn_url + '"'
cflags += _flag
endif
############################################################
# dependencies are put in the list called dependencies
#
dependencies = [ ]
############################################################
# dependencies that usually have no pkg-config
# THESE NEED TO BE SET IN $LIBRARY_PATH (or $LIBPATH on Windoze)
#
# system libraries : note that libm may not be required
# on some systems (GSL may also specify)
dependencies += [
compiler.find_library('c', required: true),
compiler.find_library('m', required: false),
]
############################################################
# libraries : required and optional.
#
# Note that optional libraries are not built in
# on a generic build.
#
_required_libraries = [
'c',
'gsl',
'gslcblas',
]
_optional_libraries = [
'backtrace',
'bfd',
'bsd',
'iberty',
'm', # optional on some platforms (gsl probably required is)
'memoize',
'rinterpolate',
]
libs = [] # list sent to the compiler
foreach libname : _required_libraries
_dep = compiler.find_library(libname,
required:true)
if _dep.found()
cflags += '-D__HAVE_LIB' + libname.to_upper() +'__'
libs += '-l' + libname
# extras
if libname == 'gsl'
# use gsl-config to find cflags, libraries, etc.
message('Adding GSL-specific flags from gsl-config')
cflags += run_command('sh','-c','gsl-config --cflags').stdout().strip().split(' ')
cflags += '-DUSE_GSL'
libs += run_command('sh','-c','gsl-config --libs').stdout().strip().split(' ')
gsl_libdirs = run_command('sh','-c','gsl-config --libs | tr " " "\n"|grep ^-L | tr "\n" " "').stdout().strip().split(' ')
libdirs += gsl_libdirs
incdirs += run_command('sh','-c','gsl-config --prefix').stdout().strip()+'/include'
endif
endif
dependencies += _dep
endforeach
# Note : this should work, but does not :(
#
#gsl_dep = dependency(
# 'gsl',
# required : true,
# version : '>=2.4',
# method : 'config-tool',
# )
#############################
# optional libraries
# libbacktrace, libbfd etc.
# (generic builds should not use these)
#
if get_option('generic') == false
foreach libname : _optional_libraries
_dep = compiler.find_library(libname,required:false)
if _dep.found()
cflags += '-D__HAVE_LIB' + libname.to_upper() +'__'
libs += '-l' + libname
endif
endforeach
endif
############################################################
# features which are converted into preprocessor flags (-D)
#
###########
# drand48 #
#
if compiler.has_header('stdlib.h') and \
compiler.sizeof('drand48_r',
prefix : '#include <stdlib.h>') > 0
cflags += '-D__HAVE_DRAND48__'
endif
############
# malloc.h #
#
if compiler.has_header('malloc.h')
cflags += '-D__HAVE_MALLOC_H__'
endif
############
# setitimer
#
if compiler.has_header('sys/time.h') and \
compiler.has_function('setitimer')
cflags += '-D__HAVE_SETITIMER__'
endif
#################################
# pkg-config (external command) #
#
if run_command('pkg-config','--version').returncode() == 0
cflags += '-D__HAVE_PKG_CONFIG__'
endif
###########################
# valgrind (header files) #
#
if compiler.has_header('valgrind/valgrind.h')
cflags += '-D__HAVE_VALGRIND__'
endif
###################
# show_starstruct #
#
if run_command('sh','-c','meson/make_starstruct.sh').returncode() == 0
cflags += '-D__SHOW_STARDATA__'
endif
###################
# diff_starstruct #
#
if run_command('sh','-c','meson/diff_starstruct.sh').returncode() == 0
cflags += '-D__DIFF_STARDATA__'
endif
########################
# Unsupported features #
#
if compiler.get_id() != 'gcc' and compiler.get_id() != 'clang'
cflags += '-UBACKTRACE'
endif
############################################################
# make a list of include directories
# We do this so that $HOME/include is searched (e.g. for
# libgsl)
#
my_incdirs = []
found = false
_include_search_paths = [
homedir + '/include',
'/usr/include',
'/usr/local/include',
]
foreach idir : _include_search_paths
inc_arg = idir
_Inc_arg = '-I' + idir
if not found and compiler.has_header('gsl/gsl_blas.h',
args: _Inc_arg)
my_incdirs += [inc_arg]
found = true
endif
endforeach
incdirs += [ my_incdirs ]
############################################################
# data objects
#
# list and build them
message('Checking and building data objects')
data_objects = run_command('meson/data_object_list_and_build.sh').stdout().strip().split(' ')
if get_option('clean_data_objects') == true
run_command('meson/clean_data_objects.sh')
endif
############################################################
# make binary_c_version_macros.h
#
run_command('meson/make_version_macros.pl')
############################################################
# source files
#
c_sourcefiles = run_command('meson/c_sourcefiles.sh').stdout().strip().split('\n')
c_main_sourcefiles = run_command('meson/c_main_sourcefiles.sh').stdout().strip().split('\n')
h_sourcefiles = run_command('meson/h_sourcefiles.sh').stdout().strip().split('\n')
############################################################
# extra quoted flags to pass into binary_c
#
cflags_with_O = cflags + [ '-O' + get_option('optimization') ] # cflags with -O<n>
cflags_quoted = ' '.join(cflags_with_O) # turn to string
cflags_quoted = ''.join(cflags_quoted.split('"')) # remove "
cflags_quoted = '-DCFLAGS=' + ''.join(['"', cflags_quoted , '"']) # surround in " ... "
cc_quoted = '-DCC="' + compiler.get_id() + '"'
ld_quoted = '-DLD="' + compiler.get_id() + '"'
incdirs_quoted = '-DINCDIRS=' + ''.join(['"-I', ' -I'.join(absolute_incdirs),'"']) # make -I... -I...
incdirs_quoted = '_slash_'.join(incdirs_quoted.split('/')) # deslash (convert / to _slash_)
libdirs_quoted = '-DLIBDIRS=' + ''.join(['"-L', ' -L'.join(absolute_libdirs),'"']) # make -L... -L...
libdirs_quoted = '_slash_'.join(libdirs_quoted.split('/')) # deslash
libs_quoted = '-DLIBS=' + ''.join(['"', ' '.join(libs),'"'])
libs_quoted = '_slash_'.join(libs_quoted.split('/'))
# hence a quoted version of the cflags
quoted_cflags_list = [
cflags_quoted,
cc_quoted,
incdirs_quoted,
ld_quoted,
libdirs_quoted,
libs_quoted,
]
############################################################
# compiler warning flags
############################################################
warn_flags = []
foreach _arg : [
'all',
'format',
'strict-prototypes',
'format-signedness'
]
_warn_arg = '-W' + _arg
if compiler.has_argument(_warn_arg)
warn_flags += _warn_arg
endif
endforeach
cflags += warn_flags
############################################################
# make precompiled headers (PCH)
#
# PCH is (sort of) supported by Meson, but not really.
# Meson supports it if you have a pre-made .pch (or .gch
# for gcc) file, but that's not the case here. We should
# generate our own pch/gch file on the file, and *also*
# its dependencies in a pch.d/gch.d file. This is a bit
# complicated, as you will see below.
#
if get_option('usepch') == true
# get optimization level, required for __OPTIMIZE__
_opt = '-O' + get_option('optimization')
# make sure we precompile with fPIC and symbols
_pic = ['-g','-fPIC']
# normal dep file
_depfile_path = binary_c_src + '/binary_c.h.gch.d'
# make a list of incdirs each prefixed by -I
_incdirs = []
foreach _i : absolute_incdirs
_I = '-I' + _i
_incdirs += _I
endforeach
_incdirs += [ '-I.' ]
# choose your compiler...
if compiler.get_id() == 'clang'
# clang PCH
_pch = 'binary_c.h.pch'
use_pch_cflags = [
'-include-pch',
_pch ]
pch_cflags = [
_opt,
_pic,
_incdirs,
]
pch_sourcefiles = [ _pch ]
pch_post = [ '-o', _pch ]
pch_depfile = ''
else
# GCC PCH
_gch = 'binary_c.h.gch'
_gchd = '../src/' + _gch + '.d'
use_pch_cflags = [ ] # -include is not required
pch_cflags = [
_opt,
_pic,
_incdirs,
'-MT', 'binary_c.h.gch',
'-MMD',
'-MP',
'-MF', _depfile_path,
'-x', 'c-header'
]
pch_sourcefiles = [ _gch ]
cflags += [
'-fpch-deps',
'-fpch-preprocess'
]
pch_post = [ ]
pch_depfile = _gch + '.d'
endif
# make cflags for pch build
pch_cflags_array = cflags + pch_cflags
# append usage flags
cflags += use_pch_cflags
# make PCH compiler: this is just the normal compiler with PCH flags
pch_compiler = compiler.cmd_array() + pch_cflags_array
message('building precompiled headers')
precompiled_headers = custom_target(
'binary_c.h.pch',
build_by_default : true,
input : ['src/binary_c.h'],
output : pch_sourcefiles,
command : [
pch_compiler,
'-gdwarf-2',
'@INPUT@',
pch_post
],
depend_files : [ h_sourcefiles ],
)
else
# disable PCH by removing the files it would have generated
all_pch_sourcefiles = [ 'binary_c.h.gch', 'binary_c.h.pch' ]
precompiled_headers = custom_target(
'binary_c.h.pch',
build_by_default : true,
input : [ 'src/binary_c.h' ],
output : all_pch_sourcefiles,
command : [ 'rm', '-f', all_pch_sourcefiles ],
depend_files : [h_sourcefiles],
)
endif
############################################################
# command to install binary_c in its 'legacy' locations
# (required for binary_grid2)
binary_c_legacy_install_cmd = [
'cp','--remove-destination','binary_c','../',
'&&',
'cp','--remove-destination','libbinary_c.so','../src/',
'&&',
'echo','libbinary_c.so built with symbols:',
'&&',
'../meson/list_shared_symbols.sh','libbinary_c.so'
]
############################################################
#
# Convenience for Rob: try to locate binary_grid2.pm and
# hence touch (and rebuild) it when the shared library is
# rebuild
#
if run_command('sh','-c','meson/check_binary_grid2.sh').returncode() == 0
binary_grid2_file = run_command(
'sh',
'-c',
'meson/check_binary_grid2.sh'
).stdout().strip()
message('legacy touch')
binary_c_legacy_install_cmd += [
'&&',
'touch',
binary_grid2_file
]
endif
############################################################
#
# symlink shared_library to binary_c/src directory
# run: ninja libbinary_c_symlink
#
libbinary_c_symlink = custom_target(
'libbinary_c_symlink',
build_by_default: false,
output: [ 'libbinary_c_symlink' ],
command: [
'sh',
'-c',
'../meson/symlink_libbinary_c.sh'
],
)
############################################################
#
# make binary_c objects
#
# We put the objects in here so they can be shared by
# the executable and library builds. We're not really
# interested in the static library, but we have to call
# this build something.
#
binary_c_objects = build_target(
'binary_c_objects',
build_by_default: true,
pic: true,
target_type : 'static_library', # pretend we're a static library!
sources : [
c_sourcefiles,
h_sourcefiles,
precompiled_headers
],
include_directories: include_directories(incdirs),
dependencies : dependencies,
c_args : [
cflags,
quoted_cflags_list,
],
objects : data_objects,
link_args : [
libs,
],
)
############################################################
#
# make shared library
# run: ninja libbinary_c.so
#
binary_c_shared_library = shared_library(
get_option('libname'),
build_by_default : false,
install: true,
include_directories: include_directories(incdirs),
dependencies : [ dependencies ],
c_args : [
cflags,
quoted_cflags_list,
'--whole-archive',
],
link_whole: [
binary_c_objects,
],
link_args : [
libs,
'-fvisibility=hidden',
],
)
############################################################
#
# make executable
# run: ninja binary_c
#
binary_c_executable = executable(
'binary_c',
build_by_default : true,
install: true,
sources : [
c_main_sourcefiles,
],
include_directories: include_directories(incdirs),
dependencies : [ dependencies ],
c_args : [
cflags,
quoted_cflags_list,
],
objects : data_objects,
link_args : [
libs,
],
link_with: [ binary_c_objects ],
)
############################################################
# install both binary_c and libbinary_c.so in their legacy
# locations
#
binary_c_install_legacy = custom_target(
'binary_c_install_legacy',
build_by_default: false,
output: [ 'binary_c_install_legacy' ],
command: binary_c_legacy_install_cmd,
depends : [
binary_c_executable,
binary_c_shared_library,
],
)