SCons:Example
SCons의 SConstruct파일 샘플.
Worldit
SConstruct file
#!/bin/python
# -*- coding: utf-8 -*-
import os
import sys
import copy
import glob
import fnmatch
import re
import library
from os.path import expanduser
HOME_DIR=expanduser('~')
LOCAL_DIR=os.path.join(HOME_DIR, '.local')
LOCAL_INC_DIR=os.path.join(LOCAL_DIR, 'include')
LOCAL_LIB_DIR=os.path.join(LOCAL_DIR, 'lib')
DEBUG_PARAM_NAME = 'debug'
DEBUG_FLAG = '-g'
SOURCE_SUFFIX_LIST = ['*.c', '*.cc', '*.cpp']
OBJECT_SUFFIX = '.o'
def existAndMkdir(dir):
if os.path.isdir(dir) == False:
os.mkdir(dir)
pass
def which(program):
path = os.getenv('PATH')
for cursor in path.split(os.path.pathsep):
cursor = os.path.join(cursor, program)
if os.path.exists(cursor) and os.access(cursor, os.X_OK):
return cursor
return ''
def toList(value):
if isinstance(value, list):
return value
else:
return [value]
pass
class Config:
def __init__(self):
self.debug = False
self.windows = False
self.posix = False
# Platform example:
# - MacOSX: darwin
# - Linux: linux2
# - Windows: win32
self.platform = sys.platform
if int(ARGUMENTS.get(DEBUG_PARAM_NAME, 0)):
self.debug = True
if os.name.upper() == 'NT':
self.windows = True
if os.name.upper() == 'POSIX':
self.posix = True
pass
def isWindows(self):
if self.platform == 'win32':
return True
else:
return False
def isLinux(self):
if self.platform == 'linux2':
return True
else:
return False
def isMacOSX(self):
if self.platform == 'darwin':
return True
else:
return False
def getInformation(self):
return { 'Debug' : self.debug
, 'Windows' : self.windows
, 'POSIX' : self.posix
, 'PLATFORM' : self.platform}
class Sources:
def __init__(self):
self.sources = []
def append(self, source):
self.sources.append(source)
def appendFromDirectory(self, directory):
for dirpath, dirnames, filenames in os.walk(directory):
for ext in SOURCE_SUFFIX_LIST:
for filename in fnmatch.filter(filenames, ext):
self.sources.append(os.path.join(dirpath, filename))
pass
def removeMatch(self, match):
for cursor in self.sources:
if re.match(match, cursor):
self.sources.remove(cursor)
pass
class Compiler:
def __init__(self, name, debug, sources, toolname = ''):
self.name = name
if debug:
self.name += DEBUG_FLAG
if toolname:
self.env = Environment(ENV = os.environ, tools = [toolname])
else:
self.env = Environment(ENV = os.environ)
if debug:
self.appendAllCflag(DEBUG_FLAG)
self.appendAllDefine('DEBUG')
else:
self.appendAllDefine('NDEBUG')
self.appendAllDefine('RELEASE')
self.objects = Compiler.createObjects(self.env, self.name, sources)
pass
@staticmethod
def getObjectName(source, suffix):
dot_index = source.rfind('.')
if suffix:
return source[:dot_index] + '.' + suffix + OBJECT_SUFFIX
else:
return source[:dot_index] + OBJECT_SUFFIX
pass
@staticmethod
def createObjects(env, name, sources):
objects = []
for cursor in sources:
objects += env.Object(Compiler.getObjectName(cursor, name), cursor)
return objects
def appendSource(self, sources):
self.objects += Compiler.createObjects(self.env, self.name, sources)
def appendAllDefine(self, define):
self.env.Append(CPPDEFINES = toList(define))
def prependAllDefine(object, define):
self.env.Prepend(CPPDEFINES = toList(define))
def appendAllCflag(self, flag):
self.env.Append(CCFLAGS = toList(flag))
def prependAllCflag(self, flag):
self.env.Prepend(CCFLAGS = toList(flag))
def appendAllCxxflag(self, flag):
self.env.Append(CXXFLAGS = toList(flag))
def prependAllCxxflag(self, flag):
self.env.Prepend(CXXFLAGS = toList(flag))
def appendAllIncludePath(self, path):
self.env.Append(CPPPATH = toList(path))
def prependAllIncludePath(self, path):
self.env.Prepend(CPPPATH = toList(path))
def parsePkgConfig(self, command):
self.env.ParseConfig(command)
def appendLibraryPath(self, path):
self.env.Append(LIBPATH = toList(path))
def prependLibraryPath(self, path):
self.env.Prepend(LIBPATH = toList(path))
def appendLibrary(self, library):
self.env.Append(LIBS = toList(library))
def prependLibrary(self, library):
self.env.Prepend(LIBS = toList(library))
def appendLinkflag(self, flag):
self.env.Append(LINKFLAGS = toList(flag))
def prependLinkflag(self, flag):
self.env.Prepend(LINKFLAGS = toList(flag))
def runProgram(self):
return self.env.Program(target = self.name, source = self.objects)
def runSharedLibrary(self):
return self.env.SharedLibrary(target = self.name, source = self.objects)
def runLibrary(self):
return self.env.Library(target = self.name, source = self.objects)
## -----------------
## Utility function.
## -----------------
def getDefaultCompiler(name, libs):
config = Config()
sources = Sources()
sources.appendFromDirectory('src/' + name)
if config.windows:
compiler = Compiler(name, config.debug, sources.sources, 'mingw')
else:
compiler = Compiler(name, config.debug, sources.sources)
if os.path.isfile('property.py'):
import property
if os.path.isdir(property.local_dir):
compiler.appendAllIncludePath(os.path.join(property.local_dir, 'include'))
compiler.appendLibraryPath(os.path.join(property.local_dir, 'lib'))
else:
compiler.appendAllIncludePath(LOCAL_INC_DIR)
compiler.appendLibraryPath(LOCAL_LIB_DIR)
if not config.isMacOSX():
compiler.appendLinkflag('-static-libstdc++')
compiler.appendAllCxxflag('-std=c++11')
compiler.appendAllIncludePath('src')
compiler.appendLibraryPath('.')
#compiler.appendLibrary(['WS2_32', 'mswsock'])
#compiler.appendLibrary('atomic')
compiler.appendLibrary(libs)
return compiler
def addThirdPartySetting(compiler, path):
sources = Sources()
sources.appendFromDirectory(path)
compiler.appendSource(sources.sources)
compiler.appendAllIncludePath(path)
return compiler
def printInformation():
print ''
print '-------------------------'
print 'WORLD SCons build script.'
print '-------------------------'
print Config().getInformation()
print ''
## ----------------
## Runner function.
## ----------------
def getWorldCompiler():
name = 'world'
libs = library.getMainStaticLibs(Config().isMacOSX())
compiler = getDefaultCompiler(name, libs)
#compiler.appendAllCflag('-Wextra') # Don't use Wextra flag.
compiler.appendAllCflag('-Wall')
# Third-party
addThirdPartySetting(compiler, 'src/3rd/sqlite')
addThirdPartySetting(compiler, 'src/3rd/lua')
addThirdPartySetting(compiler, 'src/3rd/lmdb')
compiler.appendAllDefine('LUA_COMPAT_5_2')
if not Config().debug:
compiler.appendAllCflag('-O2')
return compiler
def getWorlditCompiler():
name = 'worldit'
libs = library.getMainStaticLibs(Config().isMacOSX()) + library.getSdl2StaticLibs()
compiler = getDefaultCompiler(name, libs)
#compiler.appendAllCflag('-Wextra') # Don't use Wextra flag.
compiler.appendAllCflag('-Wall')
# Third-party
addThirdPartySetting(compiler, 'src/3rd/gfx')
if Config().windows:
compiler.appendLinkflag(['-Wl,--subsystem,windows', '-mwindows'])
if not Config().debug:
compiler.appendAllCflag('-O2')
return compiler
def getTestCompiler():
name = 'test'
libs = library.getMainStaticLibs(Config().isMacOSX()) + library.getTestStaticLibs()
return getDefaultCompiler(name, libs)
def build():
compilerWorld = getWorldCompiler()
compilerWorldit = getWorlditCompiler()
compilerTest = getTestCompiler()
compilerWorldit.prependLibrary(compilerWorld.name)
compilerTest.prependLibrary(compilerWorld.name)
world = compilerWorld.runLibrary()
worldit = compilerWorldit.runProgram()
test = compilerTest.runProgram()
Depends(worldit, world)
Depends(test, world)
pass
## ------
## RUN!!!
## ------
printInformation()
build()
library.py file
#!/bin/python
# -*- coding: utf-8 -*-
def addSuffix(array, suffix):
result = []
for cursor in array:
result += [ cursor + suffix ]
return result
def addPrefix(array, prefix):
result = []
for cursor in array:
result += [ prefix + cursor ]
return result
## ----------
## Libraries.
## ----------
BOOST_LIBS = ['boost_system', 'boost_filesystem', 'boost_locale', 'boost_log', 'boost_log_setup'
, 'boost_thread' # for the boost_log (use from basic_formatting_sink_frontend)
]
TEST_LIBS = ['boost_unit_test_framework']
SDL2_LIBS = ['SDL2', 'SDL2_image', 'SDL2_mixer', 'SDL2_ttf']
MULTI_THREADING = '-mt'
DYNAMIC_SUFFIX = '.dll'
def getBoostStaticLibs(boost_mt = False):
if boost_mt:
return addSuffix(BOOST_LIBS, MULTI_THREADING)
else:
return BOOST_LIBS
def getTestStaticLibs():
return TEST_LIBS
def getSdl2StaticLibs():
return SDL2_LIBS
def getBoostDynamicLibs(boost_mt = False):
return addSuffix(BOOST_LIBS, DYNAMIC_SUFFIX)
def getTestDynamicLibs():
return addSuffix(TEST_LIBS, DYNAMIC_SUFFIX)
def getSdl2DynamicLibs():
return addSuffix(SDL2_LIBS, DYNAMIC_SUFFIX)
## -----------------
## User's interface.
## -----------------
def getMainStaticLibs(boost_mt = False):
return getBoostStaticLibs(boost_mt)
if __name__ == '__main__':
pass
Worldit SConstruct v2
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import platform
import time
import fnmatch
import re
DOT = '.'
DASH = '-'
DEBUG_CHAR = 'g'
DEBUG_FLAG = DASH + DEBUG_CHAR
SOURCE_SUFFIX = DOT + 'cpp'
OBJECT_SUFFIX = DOT + 'o'
DEBUG_DEFINE = 'DEBUG'
NDEBUG_DEFINE = 'NDEBUG'
RELEASE_DEFINE = 'RELEASE'
## ------------
## Time & Date.
## ------------
TIME_FORMAT = r'%y%m%d_%H%M%S'
def getModification(path):
return time.localtime(os.path.getmtime(path))
def getTimestamp(time):
return time.strftime(TIME_FORMAT, time)
## ---------
## Platform.
## ---------
PLATFORM_MACOSX = 'darwin'
PLATFORM_LINUX = 'linux2'
PLATFORM_WINDOWS = 'win32'
PLATFORM_CYGWIN = 'cygwin'
PLATFORM_OS2 = 'os2'
PLATFORM_OS2_EMX = 'os2emx'
PLATFORM_RISC_OS = 'riscos'
PLATFORM_ATHE_OS = 'atheos'
PLATFORM_UNKNOWN = 'unknown'
def getPlatform():
return sys.platform
def isPosix():
return os.name.upper() == 'POSIX'
def getMachine():
return platform.machine()
## -----------------
## File & Directory.
## -----------------
CPP_SOURCE_SUFFIX_LIST = ['*.c', '*.cc', '*.cxx', '*.cpp', '*.c++']
CPP_HEADER_SUFFIX_LIST = ['*.h', '*.hh', '*.hxx', '*.hpp', '*.h++']
CPP_SUFFIX_LIST = CPP_SOURCE_SUFFIX_LIST + CPP_HEADER_SUFFIX_LIST
PROTO_SUFFIX_LIST = ['*.proto']
def findWithSuffix(directory, suffix):
result = []
for dirpath, dirnames, filenames in os.walk(directory):
for ext in suffix:
for filename in fnmatch.filter(filenames, ext):
result += [os.path.join(dirpath, filename)]
return result
def existAndMkdir(dir):
if not os.path.isdir(dir):
os.mkdir(dir)
## -----------
## Properties.
## -----------
PROPERTIES_NAME = 'properties'
CPATH_NAME = 'CPATH'
LIBRARY_PATH_NAME = 'LIBRARY_PATH'
LD_LIBRARY_PATH_NAME = 'LD_LIBRARY_PATH_NAME'
if not os.path.isfile(PROPERTIES_NAME):
with open(PROPERTIES_NAME, 'wb') as f:
f.write(CPATH_NAME + '=\n')
f.write(LIBRARY_PATH_NAME + '=\n')
f.write(LD_LIBRARY_PATH_NAME + '=\n')
def readProperties():
with open(PROPERTIES_NAME, 'rb') as f:
result = {}
for line in f:
name = str(re.match(r'^.*=', line).group()).strip()
value = str(line[len(name):]).strip()
name = str(name[:-1]).strip()
result[name] = value
return result
## ----------------
## SCons arguments.
## ----------------
DEBUG_PARAM_NAME = 'debug'
def getArgument(name, default):
return int(ARGUMENTS.get(name, default)) # NOQA
IS_DEBUG = getArgument(DEBUG_PARAM_NAME, 0)
## ----------
## FILE NAME.
## ----------
def getChangeSuffix(original, suffix):
dot_index = original.rfind(DOT)
if dot_index == -1:
return original + suffix
return original[:dot_index] + suffix
def getFlagSuffix(debug=False):
if debug:
return DEBUG_FLAG
return ''
def getDecorateName(original, suffix='', debug=False):
flags = getFlagSuffix(debug)
return getChangeSuffix(original, flags + suffix)
def getAutoDecorateName(original, suffix=''):
debug = IS_DEBUG
return getDecorateName(original, suffix, debug)
def getObjectName(original):
return getAutoDecorateName(original, OBJECT_SUFFIX)
def getObject(env, source, **dic):
obj_name = getObjectName(source)
return env.Object(obj_name, source, **dic)
## ---------------
## COMMON SETTING.
## ---------------
def setProperties(env):
properties = readProperties()
for key in properties.keys():
if properties[key]:
env.AppendENVPath(key, properties[key])
def setReleaseMode(env):
env.Append(CCFLAGS=['-O2'])
env.Append(CPPDEFINES=[NDEBUG_DEFINE, RELEASE_DEFINE])
def setDebugMode(env):
env.Append(CCFLAGS=[DEBUG_FLAG])
env.Append(CPPDEFINES=[DEBUG_DEFINE])
def setDefaultSetting(env):
if IS_DEBUG:
setDebugMode(env)
else:
setReleaseMode(env)
env.Append(CPPPATH=['src', '3rd'])
env.Append(CXXFLAGS=['-std=c++11'])
# env.Append(CCFLAGS=['-fPIC'])
# env.Append(LINKFLAGS=['-static-libstdc++'])
# env.Append(LINKFLAGS=['-stdlib=libstdc++'])
# env.Append(LIBS=['stdc++'])
## ---------
## Protobuf.
## ---------
def getProtobufObject(env, in_dir, out_dir, source, **dic):
command = 'protoc -I ' + in_dir + ' --cpp_out=' + out_dir + ' $SOURCE'
source_name = os.path.splitext(os.path.basename(source))[0]
cpp_header = os.path.join(out_dir, source_name + '.pb.h')
cpp_source = os.path.join(out_dir, source_name + '.pb.cc')
env.Command([cpp_header, cpp_source], source, [command])
return getObject(env, cpp_source, **dic)
def getProtobufObjectList(env, **dic):
out_dir = 'src/proto'
in_dir = 'src/proto'
source = findWithSuffix(in_dir, PROTO_SUFFIX_LIST)
existAndMkdir(out_dir)
result = []
for cursor in source:
result += getProtobufObject(env, in_dir, out_dir, cursor, **dic)
return result
## --------
## BUILDER.
## --------
def createEnvironment(**dic):
env = Environment(ENV=os.environ, **dic) # NOQA
setProperties(env)
return env
def createFileList(env, target, source):
result = str(target[0])
if os.path.isfile(result):
os.remove(result)
with open(result, 'wb') as f:
index = 0
while index < len(source):
f.write(str(source[index]) + '\n')
index += 1
## ----------
## Libraries.
## ----------
LIB_PROTO_PREFIX = 'proto'
LIB_THIRD_PREFIX = 'third'
LIB_MAIN_PREFIX = 'world'
def setupProtoBuilder():
env = createEnvironment()
name = LIB_PROTO_PREFIX
setDefaultSetting(env)
objs = getProtobufObjectList(env)
return env.StaticLibrary(getAutoDecorateName(name), source=objs)
def setupThirdBuilder():
env = createEnvironment()
name = LIB_THIRD_PREFIX
setDefaultSetting(env)
objs = []
for cursor in findWithSuffix('3rd', CPP_SOURCE_SUFFIX_LIST):
objs += getObject(env, cursor)
env.Append(CCFLAGS=['-w'])
env.Append(CPPDEFINES=['LUA_COMPAT_5_2'])
return env.StaticLibrary(getAutoDecorateName(name), source=objs)
def setupMainBuilder():
env = createEnvironment()
name = LIB_MAIN_PREFIX
setDefaultSetting(env)
objs = []
for cursor in findWithSuffix('src/world', CPP_SOURCE_SUFFIX_LIST):
objs += getObject(env, cursor)
env.Append(CCFLAGS=['-Wall'])
return env.StaticLibrary(getAutoDecorateName(name), source=objs)
proto = setupProtoBuilder()
third = setupThirdBuilder()
main = setupMainBuilder()
def setDefaultLibraries(env):
env.Prepend(LIBS=[getAutoDecorateName(LIB_PROTO_PREFIX),
getAutoDecorateName(LIB_THIRD_PREFIX),
getAutoDecorateName(LIB_MAIN_PREFIX)])
if getPlatform() == PLATFORM_LINUX:
env.Append(LIBS=['pthread'])
## --------
## Program.
## --------
TEST_PREFIX = 'test'
SAMPLE_PREFIX = 'sample'
def setupTestBuilder():
env = createEnvironment()
name = TEST_PREFIX
setDefaultSetting(env)
setDefaultLibraries(env)
env.Prepend(LIBS=['gtest', 'gtest_main'])
objs = []
for cursor in findWithSuffix('src/test', CPP_SOURCE_SUFFIX_LIST):
objs += getObject(env, cursor)
return env.Program(getAutoDecorateName(name), source=objs)
def setupSampleBuilder():
env = createEnvironment()
name = SAMPLE_PREFIX
setDefaultSetting(env)
setDefaultLibraries(env)
objs = []
objs += getObject(env, 'src/sample/main.cpp')
return env.Program(getAutoDecorateName(name), source=objs)
test = setupTestBuilder()
sample = setupSampleBuilder()
## ----------------
## Target settings.
## ----------------
def setDepends(target, depends):
Depends(target, depends) # NOQA
def setDefault(targets):
Default(targets) # NOQA
LIB_TARGETS = [proto, third, main]
setDepends(test, LIB_TARGETS)
setDepends(sample, LIB_TARGETS)
DEFAULT_TARGETS = LIB_TARGETS
DEFAULT_TARGETS += [test, sample]
setDefault(DEFAULT_TARGETS) # NOQA
if __name__ == '__main__':
pass