1import sys
2import os
3import imp
4from glob import glob
5
6#######################################################
7# reusable functions and data structures
8#######################################################
9def LoadTool(name, env, **kw):
10    config_path = GetBuildPath('#/Build/Tools/SCons')
11    file, path, desc = imp.find_module(name, [config_path])
12    module = imp.load_module(name, file, path, desc)
13    module.generate(env, **kw)
14
15def MergeListUnique(item_list, items):
16    for item in items:
17        if not item in item_list: item_list.append(item)
18
19def MergeItemUnique(item_list, item):
20    if not item in item_list: item_list.append(item)
21
22def GlobSources(drct, patterns, excluded_files=[]):
23    root = GetBuildPath('#'+drct)
24    files = []
25    for pattern in Split(patterns):
26        files += glob(root+'/'+pattern)
27    return [drct+'/'+os.path.basename(x) for x in  files if os.path.basename(x) not in excluded_files]
28
29def GetDirPath(dir):
30    return '#/'+dir
31
32def DeclareBuildDir(dir):
33    env.VariantDir(dir, GetDirPath(dir), duplicate=0)
34
35def GetIncludeDirs(modules, exclude=None):
36    dirs = []
37    for module in Split(modules):
38        if Modules.has_key(module) and not module == exclude:
39            dirs += Modules[module].GetIncludeDirs()
40        else:
41            dirs += [GetDirPath(module)]
42    return dirs
43
44def GetLibraries(modules):
45    libs = []
46    for module in Split(modules):
47        if Modules.has_key(module):
48            libs += Modules[module].GetLibraries()
49        else:
50            libs += [module]
51    return libs
52
53Modules = {}
54class Module:
55    def __init__(self, name, included_modules = [], linked_modules = []):
56        self.name             = name
57        self.included_modules = included_modules
58        self.linked_modules   = linked_modules
59        self.product          = []
60
61    def GetLibraries(self):
62        return self.product+GetLibraries(self.linked_modules)
63
64    def GetIncludeDirs(self):
65        return GetIncludeDirs(self.included_modules+self.build_include_dirs, self.name)
66
67class LibraryModule(Module):
68    def __init__(self, name,
69                 build_source_dirs     = ['.'],
70                 build_source_files    = {},
71                 source_root           = 'Source',
72                 build_source_pattern  = ['*.c', '*.cpp'],
73                 build_include_dirs    = [],
74                 included_modules      = [],
75                 included_only_modules = [],
76                 linked_modules        = [],
77                 environment           = None,
78                 excluded_files        = [],
79                 extra_cpp_defines     = [],
80                 shared                = False,
81                 install               = False) :
82        build_source_dirs = [source_root+'/'+drct for drct in build_source_dirs]
83        Module.__init__(self,
84                        name,
85                        Split(included_modules)+Split(included_only_modules)+Split(build_source_dirs),
86                        Split(linked_modules)+Split(included_modules))
87        self.build_include_dirs = build_include_dirs
88        if environment is None:
89            self.env = env.Clone()
90        else:
91            self.env = environment.Clone()
92        self.env.AppendUnique(CPPDEFINES = extra_cpp_defines)
93
94        # store this new object in the module dictionary
95        Modules[name] = self
96
97        # for each source drct to build, create a VariantDir
98        # to say where we want the object files to be built,
99        # and compute the list of source files to build
100        sources = []
101        for drct in Split(build_source_dirs):
102            DeclareBuildDir(drct)
103            sources += GlobSources(drct, build_source_pattern, excluded_files)
104
105        # add cherry-picked files
106        for drct in build_source_files.keys():
107            pattern = build_source_files[drct]
108            drct_path = source_root+'/'+drct
109            DeclareBuildDir(drct_path)
110            sources += GlobSources(drct_path, pattern)
111
112        # calculate our build include path
113        cpp_path = GetIncludeDirs(Split(self.build_include_dirs) + Split(build_source_dirs) + self.included_modules + self.linked_modules)
114
115        # the product is a library
116        self.env.AppendUnique(CPPPATH=cpp_path)
117        if shared is False:
118            self.product = self.env.Library(target=name, source=sources)
119        else:
120            libs = GetLibraries(Split(linked_modules))
121            self.product = self.env.SharedLibrary(target=name, LIBS=libs, source=sources)
122        self.env.Alias(name, self.product)
123
124        # copy to Targets folder
125        if install is True:
126            inst = env.Install(dir=env.GetBuildPath('#/Targets/'+env['target']+'/'+env['build_config']), source=self.product)
127            if env['build_config'] == 'Release' and env.has_key('STRIP'):
128                env.AddPostAction(inst, env['STRIP']+' $TARGETS');
129
130def Application(name, dir, deps, install = False):
131    DeclareBuildDir(dir)
132    libs = GetLibraries(deps)
133    cpp_path = GetIncludeDirs(deps)
134
135    prog = env.Program(name,
136                       GlobSources(dir, ['*.c', '*.cpp']) + env['NPT_EXTRA_EXECUTABLE_OBJECTS'],
137                       LIBS=libs, CPPPATH=cpp_path)
138    #env.Alias(name, prog)
139    if env.has_key('NPT_EXECUTABLE_POST_PROCESSOR'):
140        env.AddPostAction(prog, env['NPT_EXECUTABLE_POST_PROCESSOR'])
141
142    # copy to Targets folder
143    if install is True:
144        inst = env.Install(dir=env.GetBuildPath('#/Targets/'+env['target']+'/'+env['build_config']), source=prog)
145        if env['build_config'] == 'Release' and env.has_key('STRIP'):
146            env.AddPostAction(inst, env['STRIP']+' $TARGETS');
147
148#######################################################
149# Main Build
150#######################################################
151Import("env")
152
153### defaults
154env['NPT_EXTRA_LIBS'] = []
155env['NPT_EXTRA_EXECUTABLE_OBJECTS'] = []
156
157if (env['build_config'] == 'Debug'):
158    env.AppendUnique(CPPDEFINES=['NPT_DEBUG', 'NPT_CONFIG_ENABLE_LOGGING', 'PLATINUM_UPNP_SPECS_STRICT'])
159else:
160    env.AppendUnique(CPPDEFINES=['NDEBUG', 'NPT_CONFIG_ENABLE_LOGGING', 'PLATINUM_UPNP_SPECS_STRICT'])
161
162### try to read in any target specific configuration
163target_config_file = env.GetBuildPath('#/Build/Targets/'+env['target']+'/Config.scons')
164if os.path.exists(target_config_file):
165    # Load the target-specific config file
166    execfile(target_config_file)
167
168#######################################################
169# modules
170#
171# Usage:
172#
173# The LibraryModule() function declares a code module
174# The included_modules parameter is a list of all the modules and/or directories
175# that will be added to the include path when building this module AND to
176# the include path of any other module that depends on this one.
177# The linked_modules parameter is a list of all the modules and/or directories
178# that are necessary to build this module. These modules will be added to
179# the include path of this module, but not to that of the modules that depend
180# on this module. The modules that depend on this module, however, will
181# automatically link with the linked_modules.
182# Note that the included_modules list is automatically added to the
183# linked_modules list, so that you do not need to list in linked_modules
184# the modules that are already listed in included_modules.
185# If a module needs to export an include path to its dependents that
186# is not a module that the dependent can link with (ex: an include dir),
187# list it in the included_only_modules.
188# To summarize: included_modules should list all the modules that users
189# of the public interface should depend on; linked_modules should list
190# all the modules not listed in included_modules that are used by the
191# module's implementation only.
192#######################################################
193# Neptune
194NPT_SOURCE_ROOT = 'ThirdParty/Neptune'
195
196extra_cpp_flags = []
197neptune_extra_linked_modules = []
198if not env.has_key('NPT_CONFIG_NO_ZIP'):
199    extra_cpp_flags = ['NPT_CONFIG_ENABLE_ZIP']
200    neptune_extra_linked_modules += ['Zlib']
201
202    LibraryModule(name                  = 'Zlib',
203                  source_root           = NPT_SOURCE_ROOT,
204                  build_source_dirs     = ['ThirdParty/zlib-1.2.3'])
205
206if not env.has_key('NPT_CONFIG_NO_SSL'):
207    extra_cpp_flags += ['NPT_CONFIG_ENABLE_TLS']
208    tls_data_dirs  = ['Data/TLS']
209    tls_tests      = ['Tls1']
210    neptune_extra_linked_modules += ['axTLS']
211
212    LibraryModule(name                  = 'axTLS',
213                  source_root           = NPT_SOURCE_ROOT,
214                  build_source_dirs     = ['ThirdParty/axTLS/crypto', 'ThirdParty/axTLS/ssl', 'ThirdParty/axTLS/config/Generic'])
215else:
216    tls_data_dirs = []
217    tls_tests     = []
218
219if not env.has_key('NPT_CONFIG_NO_CRYPTO'):
220    extra_cpp_flags += ['NPT_CONFIG_ENABLE_CRYPTO']
221    neptune_excluded_files = []
222else:
223    neptune_excluded_files = ['NptCrypto.cpp', 'NptDigest.cpp']
224
225LibraryModule(name                  = 'Neptune',
226              build_source_dirs     = ['Core']+tls_data_dirs,
227              build_source_files    = env['NPT_SYSTEM_SOURCES'],
228              excluded_files        = neptune_excluded_files,
229              extra_cpp_defines     = extra_cpp_flags,
230              linked_modules        = env['NPT_EXTRA_LIBS']+neptune_extra_linked_modules,
231              source_root           = NPT_SOURCE_ROOT + '/Source')
232
233# Platinum
234LibraryModule(name               = 'Platinum',
235              build_source_dirs  = ['Core', 'Extras'],
236              build_include_dirs = ['Source/Platinum'],
237              extra_cpp_defines  = extra_cpp_flags,
238              included_modules   = ['Neptune'])
239
240# Platinum MediaServer
241LibraryModule(name               = 'PltMediaServer',
242              build_source_dirs  = ['MediaServer'],
243              included_modules   = ['Platinum'],
244              source_root        = 'Source/Devices')
245
246# Platinum MediaRenderer
247LibraryModule(name               = 'PltMediaRenderer',
248              build_source_dirs  = ['MediaRenderer'],
249              included_modules   = ['Platinum', 'PltMediaServer'],
250              source_root        = 'Source/Devices')
251
252# Platinum MediaConnect
253LibraryModule(name               = 'PltMediaConnect',
254              build_source_dirs  = ['MediaConnect'],
255              included_modules   = ['Platinum', 'PltMediaServer', 'PltMediaRenderer'],
256              excluded_files	 = ['MACFromIP.cpp'],
257              source_root        = 'Source/Devices')
258
259for app in ['MicroMediaController', 'MediaCrawler', 'MediaConnect', 'FrameStreamer']:
260    Application(name    = app,
261                dir     = 'Source/Apps/' + app,
262                deps    = ['Platinum', 'PltMediaServer', 'PltMediaRenderer', 'PltMediaConnect'],
263              	install = True)
264
265for test in ['FileMediaServer', 'MediaRenderer', 'LightSample', 'Http', 'Time']:
266    Application(name    = test+'Test',
267                dir     = 'Source/Tests/' + test,
268                deps    = ['Platinum', 'PltMediaServer', 'PltMediaRenderer', 'PltMediaConnect'],
269              	install = True)
270
271for tool in ['TextToHeader']:
272    Application(name    = tool,
273                dir     = 'Source/Tools/' + tool,
274                deps    = ['Platinum'],
275             	install = True)
276