Merge pull request #165 from uucidl/win32-scons

build on Windows with scons
This commit is contained in:
Meredith L. Patterson 2016-05-31 01:14:20 +02:00
commit 5317ad89ba
5 changed files with 167 additions and 103 deletions

View file

@ -4,10 +4,13 @@ import os.path
import platform import platform
import sys import sys
default_install_dir='/usr/local'
if platform.system() == 'Windows':
default_install_dir = 'build' # no obvious place for installation on Windows
vars = Variables(None, ARGUMENTS) vars = Variables(None, ARGUMENTS)
vars.Add(PathVariable('DESTDIR', "Root directory to install in (useful for packaging scripts)", None, PathVariable.PathIsDirCreate)) vars.Add(PathVariable('DESTDIR', 'Root directory to install in (useful for packaging scripts)', None, PathVariable.PathIsDirCreate))
vars.Add(PathVariable('prefix', "Where to install in the FHS", "/usr/local", PathVariable.PathAccept)) vars.Add(PathVariable('prefix', 'Where to install in the FHS', default_install_dir, PathVariable.PathAccept))
vars.Add(ListVariable('bindings', 'Language bindings to build', 'none', ['cpp', 'dotnet', 'perl', 'php', 'python', 'ruby'])) vars.Add(ListVariable('bindings', 'Language bindings to build', 'none', ['cpp', 'dotnet', 'perl', 'php', 'python', 'ruby']))
tools = ['default', 'scanreplace'] tools = ['default', 'scanreplace']
@ -17,6 +20,9 @@ if 'dotnet' in ARGUMENTS.get('bindings', []):
envvars = {'PATH' : os.environ['PATH']} envvars = {'PATH' : os.environ['PATH']}
if 'PKG_CONFIG_PATH' in os.environ: if 'PKG_CONFIG_PATH' in os.environ:
envvars['PKG_CONFIG_PATH'] = os.environ['PKG_CONFIG_PATH'] envvars['PKG_CONFIG_PATH'] = os.environ['PKG_CONFIG_PATH']
if platform.system() == 'Windows':
# from the scons FAQ (keywords: LNK1104 TEMPFILE), needed by link.exe
envvars['TMP'] = os.environ['TMP']
env = Environment(ENV = envvars, env = Environment(ENV = envvars,
variables = vars, variables = vars,
@ -29,7 +35,7 @@ if not 'bindings' in env:
def calcInstallPath(*elements): def calcInstallPath(*elements):
path = os.path.abspath(os.path.join(*map(env.subst, elements))) path = os.path.abspath(os.path.join(*map(env.subst, elements)))
if 'DESTDIR' in env: if 'DESTDIR' in env:
path = os.path.join(env['DESTDIR'], os.path.relpath(path, start="/")) path = os.path.join(env['DESTDIR'], os.path.relpath(path, start='/'))
return path return path
rel_prefix = not os.path.isabs(env['prefix']) rel_prefix = not os.path.isabs(env['prefix'])
@ -37,102 +43,131 @@ env['prefix'] = os.path.abspath(env['prefix'])
if 'DESTDIR' in env: if 'DESTDIR' in env:
env['DESTDIR'] = os.path.abspath(env['DESTDIR']) env['DESTDIR'] = os.path.abspath(env['DESTDIR'])
if rel_prefix: if rel_prefix:
print >>sys.stderr, "--!!-- You used a relative prefix with a DESTDIR. This is probably not what you" print >>sys.stderr, '--!!-- You used a relative prefix with a DESTDIR. This is probably not what you'
print >>sys.stderr, "--!!-- you want; files will be installed in" print >>sys.stderr, '--!!-- you want; files will be installed in'
print >>sys.stderr, "--!!-- %s" % (calcInstallPath("$prefix"),) print >>sys.stderr, '--!!-- %s' % (calcInstallPath('$prefix'),)
env['libpath'] = calcInstallPath("$prefix", "lib") env['libpath'] = calcInstallPath('$prefix', 'lib')
env['incpath'] = calcInstallPath("$prefix", "include", "hammer") env['incpath'] = calcInstallPath('$prefix', 'include', 'hammer')
env['parsersincpath'] = calcInstallPath("$prefix", "include", "hammer", "parsers") env['parsersincpath'] = calcInstallPath('$prefix', 'include', 'hammer', 'parsers')
env['backendsincpath'] = calcInstallPath("$prefix", "include", "hammer", "backends") env['backendsincpath'] = calcInstallPath('$prefix', 'include', 'hammer', 'backends')
env['pkgconfigpath'] = calcInstallPath("$prefix", "lib", "pkgconfig") env['pkgconfigpath'] = calcInstallPath('$prefix', 'lib', 'pkgconfig')
env.ScanReplace('libhammer.pc.in') env.ScanReplace('libhammer.pc.in')
env.MergeFlags("-std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-attributes -Wno-unused-variable") AddOption('--variant',
dest='variant',
nargs=1, type='choice',
choices=['debug', 'opt'],
default='opt',
action='store',
help='Build variant (debug or opt)')
AddOption('--coverage',
dest='coverage',
default=False,
action='store_true',
help='Build with coverage instrumentation')
AddOption('--in-place',
dest='in_place',
default=False,
action='store_true',
help='Build in-place, rather than in the build/<variant> tree')
AddOption('--tests',
dest='with_tests',
default=env['PLATFORM'] != 'win32',
action='store_true',
help='Build tests')
env['CC'] = os.getenv('CC') or env['CC']
env['CXX'] = os.getenv('CXX') or env['CXX']
if os.getenv('CC') == 'clang' or env['PLATFORM'] == 'darwin':
env.Replace(CC='clang',
CXX='clang++')
# Language standard and warnings
if env['CC'] == 'cl':
env.MergeFlags('-W3 -WX')
env.Append(
CPPDEFINES=[
'_CRT_SECURE_NO_WARNINGS' # allow uses of sprintf
],
CFLAGS=[
'-wd4018', # 'expression' : signed/unsigned mismatch
'-wd4244', # 'argument' : conversion from 'type1' to 'type2', possible loss of data
'-wd4267', # 'var' : conversion from 'size_t' to 'type', possible loss of data
]
)
else:
env.MergeFlags('-std=gnu99 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-attributes -Wno-unused-variable')
# Linker options
if env['PLATFORM'] == 'darwin': if env['PLATFORM'] == 'darwin':
env.Append(SHLINKFLAGS = '-install_name ' + env["libpath"] + '/${TARGET.file}') env.Append(SHLINKFLAGS = '-install_name ' + env['libpath'] + '/${TARGET.file}')
elif os.uname()[0] == "OpenBSD": elif platform.system() == 'OpenBSD':
pass
elif env['PLATFORM'] == 'win32':
# no extra lib needed
pass pass
else: else:
env.MergeFlags("-lrt") env.MergeFlags('-lrt')
AddOption("--variant", if GetOption('coverage'):
dest="variant", env.Append(CFLAGS=['--coverage'],
nargs=1, type="choice", CXXFLAGS=['--coverage'],
choices=["debug", "opt"], LDFLAGS=['--coverage'])
default="opt", if env['CC'] == 'gcc':
action="store",
help="Build variant (debug or opt)")
AddOption("--coverage",
dest="coverage",
default=False,
action="store_true",
help="Build with coverage instrumentation")
AddOption("--in-place",
dest="in_place",
default=False,
action="store_true",
help="Build in-place, rather than in the build/<variant> tree")
dbg = env.Clone(VARIANT='debug')
dbg.Append(CCFLAGS=['-g'])
opt = env.Clone(VARIANT='opt')
opt.Append(CCFLAGS=["-O3"])
if GetOption("variant") == 'debug':
env = dbg
else:
env = opt
env["CC"] = os.getenv("CC") or env["CC"]
env["CXX"] = os.getenv("CXX") or env["CXX"]
if GetOption("coverage"):
env.Append(CFLAGS=["--coverage"],
CXXFLAGS=["--coverage"],
LDFLAGS=["--coverage"])
if env["CC"] == "gcc":
env.Append(LIBS=['gcov']) env.Append(LIBS=['gcov'])
else: else:
env.ParseConfig('llvm-config --ldflags') env.ParseConfig('llvm-config --ldflags')
if os.getenv("CC") == "clang" or env['PLATFORM'] == 'darwin': dbg = env.Clone(VARIANT='debug')
env.Replace(CC="clang", if env['CC'] == 'cl':
CXX="clang++") dbg.Append(CCFLAGS=['/Z7'])
else:
dbg.Append(CCFLAGS=['-g'])
env["ENV"].update(x for x in os.environ.items() if x[0].startswith("CCC_")) opt = env.Clone(VARIANT='opt')
if env['CC'] == 'cl':
opt.Append(CCFLAGS=['/O2'])
else:
opt.Append(CCFLAGS=['-O3'])
if GetOption('variant') == 'debug':
env = dbg
else:
env = opt
env['ENV'].update(x for x in os.environ.items() if x[0].startswith('CCC_'))
#rootpath = env['ROOTPATH'] = os.path.abspath('.') #rootpath = env['ROOTPATH'] = os.path.abspath('.')
#env.Append(CPPPATH=os.path.join('#', "hammer")) #env.Append(CPPPATH=os.path.join('#', 'hammer'))
testruns = [] testruns = []
targets = ["$libpath", targets = ['$libpath',
"$incpath", '$incpath',
"$parsersincpath", '$parsersincpath',
"$backendsincpath", '$backendsincpath',
"$pkgconfigpath"] '$pkgconfigpath']
Export('env') Export('env')
Export('testruns') Export('testruns')
Export('targets') Export('targets')
if not GetOption("in_place"): if not GetOption('in_place'):
env['BUILD_BASE'] = 'build/$VARIANT' env['BUILD_BASE'] = 'build/$VARIANT'
lib = env.SConscript(["src/SConscript"], variant_dir='$BUILD_BASE/src') lib = env.SConscript(['src/SConscript'], variant_dir='$BUILD_BASE/src')
env.Alias("examples", env.SConscript(["examples/SConscript"], variant_dir='$BUILD_BASE/examples')) env.Alias('examples', env.SConscript(['examples/SConscript'], variant_dir='$BUILD_BASE/examples'))
else: else:
env['BUILD_BASE'] = '.' env['BUILD_BASE'] = '.'
lib = env.SConscript(["src/SConscript"]) lib = env.SConscript(['src/SConscript'])
env.Alias(env.SConscript(["examples/SConscript"])) env.Alias(env.SConscript(['examples/SConscript']))
for testrun in testruns: for testrun in testruns:
env.Alias("test", testrun) env.Alias('test', testrun)
env.Alias("install", targets) env.Alias('install', targets)

View file

@ -1,9 +1,16 @@
platform: platform:
- x86 - x86
- x64 - x64
environment:
PYTHON: "C:\\Python27"
version: 1.0.{build} version: 1.0.{build}
os: Visual Studio 2015 os: Visual Studio 2015
install:
- SET "PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
- easy_install scons
build_script: build_script:
- scons --version
- scons install
- '@echo off' - '@echo off'
- setlocal - setlocal
- ps: >- - ps: >-

View file

@ -1,23 +1,24 @@
# -*- python -*- # -*- python -*-
import os.path import os.path
Import('env testruns') Import('env testruns')
dist_headers = [ dist_headers = [
"hammer.h", 'hammer.h',
"allocator.h", 'allocator.h',
"compiler_specifics.h", 'compiler_specifics.h',
"glue.h", 'glue.h',
"internal.h", 'internal.h',
"platform.h" 'platform.h'
] ]
parsers_headers = [ parsers_headers = [
"parsers/parser_internal.h" 'parsers/parser_internal.h'
] ]
backends_headers = [ backends_headers = [
"backends/regex.h", 'backends/regex.h',
"backends/contextfree.h" 'backends/contextfree.h'
] ]
parsers = ['parsers/%s.c'%s for s in parsers = ['parsers/%s.c'%s for s in
@ -48,7 +49,7 @@ parsers = ['parsers/%s.c'%s for s in
'unimplemented', 'unimplemented',
'whitespace', 'whitespace',
'xor', 'xor',
'value']] 'value']]
backends = ['backends/%s.c' % s for s in backends = ['backends/%s.c' % s for s in
['packrat', 'llk', 'regex', 'glr', 'lalr', 'lr', 'lr0']] ['packrat', 'llk', 'regex', 'glr', 'lalr', 'lr', 'lr0']]
@ -63,11 +64,18 @@ misc_hammer_parts = [
'desugar.c', 'desugar.c',
'glue.c', 'glue.c',
'hammer.c', 'hammer.c',
'platform_bsdlike.c',
'pprint.c', 'pprint.c',
'registry.c', 'registry.c',
'system_allocator.c'] 'system_allocator.c']
if env['PLATFORM'] == 'win32':
misc_hammer_parts += [
'platform_win32.c',
'tsearch.c',
]
else:
misc_hammer_parts += ['platform_bsdlike.c']
ctests = ['t_benchmark.c', ctests = ['t_benchmark.c',
't_bitreader.c', 't_bitreader.c',
't_bitwriter.c', 't_bitwriter.c',
@ -76,26 +84,40 @@ ctests = ['t_benchmark.c',
't_misc.c', 't_misc.c',
't_regression.c'] 't_regression.c']
static_library_name = 'hammer'
build_shared_library=True
if env['PLATFORM'] == 'win32':
# FIXME(windows): symbols in hammer are not exported yet, a shared lib would be useless
build_shared_library=False
# prevent collision between .lib from dll and .lib for static lib
static_library_name = 'hammer_s'
libhammer_shared = env.SharedLibrary('hammer', parsers + backends + misc_hammer_parts) libhammer_shared = env.SharedLibrary('hammer', parsers + backends + misc_hammer_parts)
libhammer_static = env.StaticLibrary('hammer', parsers + backends + misc_hammer_parts) libhammer_static = env.StaticLibrary(static_library_name, parsers + backends + misc_hammer_parts)
Default(libhammer_shared, libhammer_static) if build_shared_library:
Default(libhammer_shared, libhammer_static)
env.Install('$libpath', [libhammer_static, libhammer_shared])
else:
Default(libhammer_static)
env.Install('$libpath', [libhammer_static])
env.Install("$libpath", [libhammer_static, libhammer_shared]) env.Install('$incpath', dist_headers)
env.Install("$incpath", dist_headers) env.Install('$parsersincpath', parsers_headers)
env.Install("$parsersincpath", parsers_headers) env.Install('$backendsincpath', backends_headers)
env.Install("$backendsincpath", backends_headers) env.Install('$pkgconfigpath', '../../../libhammer.pc')
env.Install("$pkgconfigpath", "../../../libhammer.pc")
testenv = env.Clone() if GetOption('with_tests'):
testenv.ParseConfig('pkg-config --cflags --libs glib-2.0') testenv = env.Clone()
testenv.Append(LIBS=['hammer']) testenv.ParseConfig('pkg-config --cflags --libs glib-2.0')
testenv.Prepend(LIBPATH=['.']) testenv.Append(LIBS=['hammer'])
ctestexec = testenv.Program('test_suite', ctests + ['test_suite.c'], LINKFLAGS="--coverage" if testenv.GetOption("coverage") else None) testenv.Prepend(LIBPATH=['.'])
ctest = Alias('testc', [ctestexec], "".join(["env LD_LIBRARY_PATH=", os.path.dirname(ctestexec[0].path), " ", ctestexec[0].path])) ctestexec = testenv.Program('test_suite', ctests + ['test_suite.c'], LINKFLAGS='--coverage' if testenv.GetOption('coverage') else None)
AlwaysBuild(ctest) ctest = Alias('testc', [ctestexec], ''.join(['env LD_LIBRARY_PATH=', os.path.dirname(ctestexec[0].path), ' ', ctestexec[0].path]))
testruns.append(ctest) AlwaysBuild(ctest)
testruns.append(ctest)
Export("libhammer_static libhammer_shared") Export('libhammer_static libhammer_shared')
for b in env['bindings']: for b in env['bindings']:
env.SConscript(["bindings/%s/SConscript" % b]) env.SConscript(['bindings/%s/SConscript' % b])

View file

@ -24,8 +24,8 @@ cl.exe -nologo -FC -EHsc -Z7 -Oi -GR- -Gm- %CLFLAGS% -c ^
-Fo%BUILD%\obj\ -Fo%BUILD%\obj\
if %errorlevel% neq 0 goto err if %errorlevel% neq 0 goto err
lib.exe %BUILD%\obj\*.obj -OUT:%BUILD%\hammer.lib lib.exe %BUILD%\obj\*.obj -OUT:%BUILD%\lib\hammer_s.lib
echo STATIC_LIBRARY %BUILD%\hammer.lib echo STATIC_LIBRARY %BUILD%\lib\hammer_s.lib
if %errorlevel% neq 0 goto err if %errorlevel% neq 0 goto err
popd popd

View file

@ -15,7 +15,7 @@ call %HEREPATH%\clvars.bat
echo SRC=%SRC%, BUILD=%BUILD% echo SRC=%SRC%, BUILD=%BUILD%
echo CLFLAGS=%CLFLAGS% echo CLFLAGS=%CLFLAGS%
set HAMMERLIB=%BUILD%\hammer.lib set HAMMERLIB=%BUILD%\lib\hammer_s.lib
REM Now let's build some example programs REM Now let's build some example programs