Skip to content
Snippets Groups Projects
meson.build 26.75 KiB
############################################################
# meson build file for binary_c
# 
# (c) Robert Izzard 25/11/2019
#
# Known to work with binary_c 2.1.4 using gcc and clang.
#
# Supporting scripts are in the meson directory of binary_c.
#
# You may well require: bash, gawk, cp, grep, wc, tr, head
#                       and perl. These are standard tools on
#                       most systems.
#
# You certainly require a C compiler (e.g. gcc or clang),
# python3 and ninja.
#
# Please see the binary_c installation documentation
# in the doc/ directory of binary_c or
# http://personal.ph.surrey.ac.uk/~ri0005/doc/binary_c/binary_c.html
#
############################################################

############################################################
# 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.
#
############################################################
# define the binary_c project
#
project(
    'binary_c','c',
    default_options : [
        'c_std=gnu99',
    ],
    version : '2.1.5', # should agree with binary_c_version.h
)

############################################################
# require Meson 0.52.0 or later
#
find_program('meson',
             version: '>=0.52.0')

############################################################
# require Ninja 1.8.2 or later
#
find_program('ninja',
             version: '>=1.8.2')

############################################################
# compiler object
#
compiler = meson.get_compiler('c')

############################################################
# exit if compiler is buggy/unsupported
#
if compiler.get_id() == 'gcc' and \
   compiler.version() == '4.7.4'
    error('gcc 4.7.4 is buggy and hence unsupported : please upgrade!')
endif

############################################################
# System information
#
# e.g. cpu frequency
#
if(host_machine.cpu_family() == 'x86_64')
    # test on 64-bit Intels
    _cpufreq = compiler.run( '''
#include <stdio.h>
#include <cpuid.h>
int main(void) 
{
    /* code based on Linux' turbostat.c by Intel (GPL2) */
    unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0, max_level = 0;
    __get_cpuid(0, &max_level, &ebx, &ecx, &edx);
    /* only works on Skylake (level 0x16) and later */
    if (max_level >= 0x16) 
    {
        unsigned int base_mhz = 0, max_mhz = 0, bus_mhz = 0;
        __get_cpuid(0x16, &base_mhz, &max_mhz, &bus_mhz, &edx);
        fprintf(stdout,"%u",max_mhz);
        return 1;
    } 
    else
    {
        fprintf(stdout,"0");
        return 0;
    }
}''')
else
    _cpufreq = compiler.run('this should error')
endif

if _cpufreq.compiled() == true and _cpufreq.returncode() != 0
    # use result of above code to extract CPU Mhz
    cpufreq = _cpufreq.stdout()
else
    # fallback script to use system tools
    cpufreq = run_command('meson/cpu_frequency.sh').stdout().strip()
endif
message('CPU frequency ' + cpufreq + 'MHz')

############################################################
# 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'

############################################################
# binary_c version
#
binary_c_version = compiler.run('''
#include <stdio.h>
#include "''' + binary_c_src + '''/binary_c_version.h"
int main(int argc,char **argv)
{
        fprintf(stdout,"%s",BINARY_C_VERSION);
        return 0;
}''').stdout().strip()  

############################################################
# the binary_c version should be the same as the project
# version: exit if not!
#
if binary_c_version != meson.project_version()
    error('binary_c_version and meson.project_version are not the same : they should be!')
else
    message('binary_c version is ' + binary_c_version)
endif

############################################################
# 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 = [
]

############################################################
# Data alignment: the longest native data type binary_c
# uses is double, so select this for alignment.
#
alignsize = '-DALIGNSIZE=' + compiler.alignment('double').to_string() 

############################################################
# default C flags
#
cflags = [
    alignsize
]
executable_build_flags = [
]

############################################################
# 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
    foreach _flag : [ '-fbracket-depth=512' ]
        if compiler.has_argument(_flag)
            cflags += _flag
        else
            error('clang requires ' + _flag + ' to build, but this flag is not available')
        endif
    endforeach

    # for some reason we require an extra fPIC
    # when building the executable *only*
    executable_build_flags += '-fPIC'
else
    # gcc-specific flags
    cflags += []
endif

############################################################
# system options
#
if cpufreq != ''
    cflags += '-DCPUFREQ=' + cpufreq
endif

############################################################
# operating system flags
#
os = host_machine.system()
cflags += [
    '-DOPERATING_SYSTEM=' + os
    ]
if os == 'linux'
    # Linux system
    cflags += [
        '-DLINUX',
        '-DPOSIX',
        '-DLARGEFILE_SOURCE'
    ]
    unix = true
    posix = true
elif os == 'darwin'
    # darwin (MacOSX)
    cflags += [
        '-DDARWIN',
        '-DPOSIX',
    ]
    unix = true
    posix = true
elif os == 'windows'
    # windows
    cflags += [
        '-DWINDOWS',
    ]
    unix = false
    posix = false
else
    cflags += [
        '-DUNKNOWN_OPERATING_SYSTEM'
    ]
    unix = false
    posix = false
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 (but gsl requires it)
    'memoize',
    'rinterpolate',
]
libs = [] # list sent to the compiler
foreach libname : _required_libraries
    _dep = compiler.find_library(libname,
                                 required:true) 
    if _dep.found()
        libs += '-l' + libname
        cflags += '-D__HAVE_LIB' + libname.to_upper() +'__'
    
        # 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 = []
            foreach gsl_libdir :run_command('sh','-c','gsl-config  --libs').stdout().strip().split(' ')
                if gsl_libdir.startswith('-L')
                    gsl_libdirs += gsl_libdir
                endif
            endforeach
            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


############################################################
# 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
    if run_command('sh','-c','meson/directory_exists.sh',idir).returncode() == 0
        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
    endif
endforeach

incdirs += [ my_incdirs ]

############################################################
# features which are converted into preprocessor flags (-D)
#

###########
# drand48 #
#
if compiler.has_header('stdlib.h',
                       args: cflags,
                       include_directories: include_directories(incdirs)\
                      ) and \
   compiler.sizeof('drand48_r',
                   prefix : '#include <stdlib.h>') > 0
    cflags += '-D__HAVE_DRAND48__'
endif

############
# malloc.h #
#
if compiler.has_header('malloc.h',
                       args: cflags,
                       include_directories: include_directories(incdirs))
    cflags += '-D__HAVE_MALLOC_H__'
endif

############ 
# setitimer 
#
if compiler.has_header('sys/time.h',
                       args: cflags,
                       include_directories: include_directories(incdirs)) 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',
                       args: cflags,
                       include_directories: include_directories(incdirs))
    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

##########################
# location of libiberty.h
#
if compiler.has_header('libiberty.h',
                       args: cflags,
                       include_directories: include_directories(incdirs))
    # Fedora
    cflags += '-D__HAVE_LIBIBERTYH__'
elif compiler.has_header('libiberty/libiberty.h',
                         args: cflags,
                         include_directories: include_directories(incdirs))
    # Debian and derivatives e.g. Ubuntu
    cflags += '-D__HAVE_LIBIBERTY_LIBIBERTYH__'
else
    error('cannot find libiberty.h at either <libiberty.h> or <libiberty/libiberty.h>')
endif

############################################################
# 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

    # 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 ],
    )

    # append usage flags for normal build
    cflags += use_pch_cflags

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)
#
# NB will only work on Unix-compatibles
#
# TODO use meson's installation instead of my own
if unix 
    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'
    ]
else
    binary_c_legacy_install_cmd = [
        'echo','"Legacy install not supported on this operating system"'
        ]
endif

############################################################
#
# Convenience for Rob: try to locate binary_grid2.pm and
# hence touch (and rebuild) it when the shared library is
# rebuild
#

if os == 'linux' and \
   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
#
# NB only works if we can symlink, i.e. unix systems
#
if unix
    libbinary_c_symlink = custom_target(
        'libbinary_c_symlink',
        build_by_default: false,
        output: [ 'libbinary_c_symlink' ],
        command: [
            'sh',
            '-c',
            '../meson/symlink_libbinary_c.sh'
        ],
    )
endif


############################################################
#
# make binary_c objects
#
# We put the objects in this build target so they can be 
# shared by the executable and library builds.
#
# We're not really interested in the static libraries that
# result, but they are joined later into one big library.
#
# Note: in theory this step is not required, we could just
# link all the .o files. The problem is that there are
# many .o files and this makes the command line too long
# (even in Linux) which means the linking fails.
#
binary_c_subdir_objects = []

src_subdirs = run_command('meson/source_directories.sh').stdout().strip().split('\n')
src_root_sourcefiles = run_command('meson/source_files.sh','./src').stdout().strip().split('\n')

# build the objects from each subdir into their own static library
foreach src_subdir : src_subdirs
    _target_name = 'binary_c_objects_' + src_subdir.underscorify()
    #message('src subdir : ' + src_subdir)
        
    # count the number of source and header files in this subdir
    _source_count = run_command('meson/count_source_files.sh',src_subdir).stdout().strip().to_int()
    _header_count = run_command('meson/count_header_files.sh',src_subdir).stdout().strip().to_int()

    #message('source file count ' + _source_count.to_string())
    #message('header file count ' + _header_count.to_string())
    
    # if we have source files, proceed
    if _source_count > 0

        # get a list of the source files for compilation
        _sources = run_command('meson/source_files.sh',src_subdir).stdout().strip().split('\n')
        #message('sources : ' + ' '.join(_sources))
        
        # get the headers (or an empty list if there are none)
        if _header_count > 0
            _headers = run_command('meson/header_files.sh',src_subdir).stdout().strip().split('\n')
        else
            _headers = []
        endif
        #message('headers : ' + ' '.join(_sources))

        # make the build target and append to binary_c_subdir_objects
        binary_c_subdir_objects += build_target(
            _target_name,
            build_by_default: false,
            pic : true,
            target_type : 'static_library',
            sources : [
                precompiled_headers,
                _sources,
                _headers,
            ],
            include_directories: include_directories(incdirs),
            c_args : [
                cflags,
                quoted_cflags_list,
            ],
            link_language: 'c',
        )
    endif
endforeach

############################################################
#
# binary_c objects references all the binary_c_subdir_objects,
# as well as the src/*.c files, so makes one static library
# with everything in it.
#
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 : [
        precompiled_headers,
        src_root_sourcefiles,
        h_sourcefiles,
    ],
    include_directories: include_directories(incdirs),
    dependencies : [ 
        dependencies,
    ],
    c_args : [
        cflags,
    ],
    objects : [
        data_objects,
        ],
    link_args : [
        libs,
    ],
    link_with : [
        binary_c_subdir_objects,
    ],
    link_language: 'c',
)

############################################################
#
# 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 : [
        precompiled_headers,
        c_main_sourcefiles,
    ],
    include_directories: include_directories(incdirs),
    dependencies : [
        dependencies
    ],
    c_args : [
        cflags,
        quoted_cflags_list,
        executable_build_flags,
    ],
    objects : data_objects,
    link_args : [
        libs,
    ],
    link_with: [
        binary_c_objects
    ],    
)

############################################################
# install both binary_c and libbinary_c.so in their legacy
# locations. run: ninja binary_c_install_legacy
#
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,
    ],
)