Merge branch 'v0.4'
[platform/upstream/nodejs.git] / wscript
1 #!/usr/bin/env python
2
3 # Copyright Joyent, Inc. and other Node contributors.
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to permit
10 # persons to whom the Software is furnished to do so, subject to the
11 # following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
19 # NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
20 # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 # USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 import re
25 import Options
26 import sys, os, shutil, glob
27 import Utils
28 from Utils import cmd_output
29 from os.path import join, dirname, abspath, normpath
30 from logging import fatal
31
32 cwd = os.getcwd()
33 APPNAME="node.js"
34
35 # Use the directory that this file is found in to find the tools
36 # directory where the js2c.py file can be found.
37 sys.path.append(sys.argv[0] + '/tools');
38 import js2c
39
40 srcdir = '.'
41 blddir = 'build'
42 supported_archs = ('arm', 'ia32', 'x64') # 'mips' supported by v8, but not node
43
44 jobs=1
45 if os.environ.has_key('JOBS'):
46   jobs = int(os.environ['JOBS'])
47
48 def safe_path(path):
49   return path.replace("\\", "/")
50
51 def canonical_cpu_type(arch):
52   m = {'x86': 'ia32', 'i386':'ia32', 'x86_64':'x64', 'amd64':'x64'}
53   if arch in m: arch = m[arch]
54   if not arch in supported_archs:
55     raise Exception("supported architectures are "+', '.join(supported_archs)+\
56                     " but NOT '" + arch + "'.")
57   return arch
58
59 def set_options(opt):
60   # the gcc module provides a --debug-level option
61   opt.tool_options('compiler_cxx')
62   opt.tool_options('compiler_cc')
63   opt.tool_options('misc')
64   opt.add_option( '--libdir'
65                 , action='store'
66                 , type='string'
67                 , default=False
68                 , help='Install into this libdir [Default: ${PREFIX}/lib]'
69                 )
70   opt.add_option( '--debug'
71                 , action='store_true'
72                 , default=False
73                 , help='Build debug variant [Default: False]'
74                 , dest='debug'
75                 )
76   opt.add_option( '--profile'
77                 , action='store_true'
78                 , default=False
79                 , help='Enable profiling [Default: False]'
80                 , dest='profile'
81                 )
82   opt.add_option( '--efence'
83                 , action='store_true'
84                 , default=False
85                 , help='Build with -lefence for debugging [Default: False]'
86                 , dest='efence'
87                 )
88
89   opt.add_option( '--without-snapshot'
90                 , action='store_true'
91                 , default=False
92                 , help='Build without snapshotting V8 libraries. You might want to set this for cross-compiling. [Default: False]'
93                 , dest='without_snapshot'
94                 )
95
96   opt.add_option( '--without-ssl'
97                 , action='store_true'
98                 , default=False
99                 , help='Build without SSL'
100                 , dest='without_ssl'
101                 )
102
103
104   opt.add_option('--shared-v8'
105                 , action='store_true'
106                 , default=False
107                 , help='Link to a shared V8 DLL instead of static linking'
108                 , dest='shared_v8'
109                 )
110
111   opt.add_option( '--shared-v8-includes'
112                 , action='store'
113                 , default=False
114                 , help='Directory containing V8 header files'
115                 , dest='shared_v8_includes'
116                 )
117
118   opt.add_option( '--shared-v8-libpath'
119                 , action='store'
120                 , default=False
121                 , help='A directory to search for the shared V8 DLL'
122                 , dest='shared_v8_libpath'
123                 )
124
125   opt.add_option( '--shared-v8-libname'
126                 , action='store'
127                 , default=False
128                 , help="Alternative lib name to link to (default: 'v8')"
129                 , dest='shared_v8_libname'
130                 )
131
132   opt.add_option( '--openssl-includes'
133                 , action='store'
134                 , default=False
135                 , help='A directory to search for the OpenSSL includes'
136                 , dest='openssl_includes'
137                 )
138
139   opt.add_option( '--openssl-libpath'
140                 , action='store'
141                 , default=False
142                 , help="A directory to search for the OpenSSL libraries"
143                 , dest='openssl_libpath'
144                 )
145
146   opt.add_option( '--gdb'
147                 , action='store_true'
148                 , default=False
149                 , help="add gdb support"
150                 , dest='use_gdbjit'
151                 )
152
153
154   opt.add_option('--shared-cares'
155                 , action='store_true'
156                 , default=False
157                 , help='Link to a shared C-Ares DLL instead of static linking'
158                 , dest='shared_cares'
159                 )
160
161   opt.add_option( '--shared-cares-includes'
162                 , action='store'
163                 , default=False
164                 , help='Directory containing C-Ares header files'
165                 , dest='shared_cares_includes'
166                 )
167
168   opt.add_option( '--shared-cares-libpath'
169                 , action='store'
170                 , default=False
171                 , help='A directory to search for the shared C-Ares DLL'
172                 , dest='shared_cares_libpath'
173                 )
174
175
176   opt.add_option('--shared-libev'
177                 , action='store_true'
178                 , default=False
179                 , help='Link to a shared libev DLL instead of static linking'
180                 , dest='shared_libev'
181                 )
182
183   opt.add_option( '--shared-libev-includes'
184                 , action='store'
185                 , default=False
186                 , help='Directory containing libev header files'
187                 , dest='shared_libev_includes'
188                 )
189
190   opt.add_option( '--shared-libev-libpath'
191                 , action='store'
192                 , default=False
193                 , help='A directory to search for the shared libev DLL'
194                 , dest='shared_libev_libpath'
195                 )
196
197   opt.add_option( '--with-dtrace'
198                 , action='store_true'
199                 , default=False
200                 , help='Build with DTrace (experimental)'
201                 , dest='dtrace'
202                 )
203  
204
205   opt.add_option( '--product-type'
206                 , action='store'
207                 , default='program'
208                 , help='What kind of product to produce (program, cstaticlib '\
209                        'or cshlib) [default: %default]'
210                 , dest='product_type'
211                 )
212
213   opt.add_option( '--dest-cpu'
214                 , action='store'
215                 , default=None
216                 , help='CPU architecture to build for. Valid values are: '+\
217                        ', '.join(supported_archs)
218                 , dest='dest_cpu'
219                 )
220
221
222
223
224 def configure(conf):
225   conf.check_tool('compiler_cxx')
226   if not conf.env.CXX: conf.fatal('c++ compiler not found')
227   conf.check_tool('compiler_cc')
228   if not conf.env.CC: conf.fatal('c compiler not found')
229
230   o = Options.options
231
232   if o.libdir:
233     conf.env['LIBDIR'] = o.libdir
234   else:
235     conf.env['LIBDIR'] = conf.env['PREFIX'] + '/lib'
236
237   conf.env["USE_DEBUG"] = o.debug
238   # Snapshot building does noet seem to work on cygwin and mingw32
239   conf.env["SNAPSHOT_V8"] = not o.without_snapshot and not sys.platform.startswith("win32")
240   if sys.platform.startswith("sunos"):
241     conf.env["SNAPSHOT_V8"] = False
242   conf.env["USE_PROFILING"] = o.profile
243
244   conf.env["USE_SHARED_V8"] = o.shared_v8 or o.shared_v8_includes or o.shared_v8_libpath or o.shared_v8_libname
245   conf.env["USE_SHARED_CARES"] = o.shared_cares or o.shared_cares_includes or o.shared_cares_libpath
246   conf.env["USE_SHARED_LIBEV"] = o.shared_libev or o.shared_libev_includes or o.shared_libev_libpath
247
248   conf.env["USE_GDBJIT"] = o.use_gdbjit
249
250   conf.check(lib='dl', uselib_store='DL')
251   if not sys.platform.startswith("sunos") and not sys.platform.startswith("cygwin") and not sys.platform.startswith("win32"):
252     conf.env.append_value("CCFLAGS", "-rdynamic")
253     conf.env.append_value("LINKFLAGS_DL", "-rdynamic")
254
255   if sys.platform.startswith("freebsd") or sys.platform.startswith("openbsd"):
256     conf.check(lib='kvm', uselib_store='KVM')
257
258   #if Options.options.debug:
259   #  conf.check(lib='profiler', uselib_store='PROFILER')
260
261   if Options.options.dtrace:
262     if not sys.platform.startswith("sunos"):
263       conf.fatal('DTrace support only currently available on Solaris')
264
265     conf.find_program('dtrace', var='DTRACE', mandatory=True)
266     conf.env["USE_DTRACE"] = True
267     conf.env.append_value("CXXFLAGS", "-DHAVE_DTRACE=1")
268
269   if Options.options.efence:
270     conf.check(lib='efence', libpath=['/usr/lib', '/usr/local/lib'], uselib_store='EFENCE')
271
272   if sys.platform.startswith("freebsd"):
273      if not conf.check(lib="execinfo",
274                        includes=['/usr/include', '/usr/local/include'],
275                        libpath=['/usr/lib', '/usr/local/lib'],
276                        uselib_store="EXECINFO"):
277        conf.fatal("Install the libexecinfo port from /usr/ports/devel/libexecinfo.")
278
279   if not Options.options.without_ssl:
280     # Don't override explicitly supplied openssl paths with pkg-config results.
281     explicit_openssl = o.openssl_includes or o.openssl_libpath
282     if not explicit_openssl and conf.check_cfg(package='openssl',
283                                                args='--cflags --libs',
284                                                uselib_store='OPENSSL'):
285       Options.options.use_openssl = conf.env["USE_OPENSSL"] = True
286       conf.env.append_value("CPPFLAGS", "-DHAVE_OPENSSL=1")
287     else:
288       if o.openssl_libpath: 
289         openssl_libpath = [o.openssl_libpath]
290       elif not sys.platform.startswith('win32'):
291         openssl_libpath = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/usr/sfw/lib']
292       else:
293         openssl_libpath = [normpath(join(cwd, '../openssl'))]
294
295       if o.openssl_includes: 
296         openssl_includes = [o.openssl_includes]
297       elif not sys.platform.startswith('win32'):
298         openssl_includes = [];
299       else:
300         openssl_includes = [normpath(join(cwd, '../openssl/include'))];
301
302       openssl_lib_names = ['ssl', 'crypto']
303       if sys.platform.startswith('win32'):
304         openssl_lib_names += ['ws2_32', 'gdi32']
305
306       libssl = conf.check_cc(lib=openssl_lib_names,
307                              header_name='openssl/ssl.h',
308                              function_name='SSL_library_init',
309                              includes=openssl_includes,
310                              libpath=openssl_libpath,
311                              uselib_store='OPENSSL')
312
313       libcrypto = conf.check_cc(lib='crypto',
314                                 header_name='openssl/crypto.h',
315                                 includes=openssl_includes,
316                                 libpath=openssl_libpath,
317                                 uselib_store='OPENSSL')
318
319       if libcrypto and libssl:
320         conf.env["USE_OPENSSL"] = Options.options.use_openssl = True
321         conf.env.append_value("CPPFLAGS", "-DHAVE_OPENSSL=1")
322       elif sys.platform.startswith('win32'):
323         conf.fatal("Could not autodetect OpenSSL support. " +
324                    "Use the --openssl-libpath and --openssl-includes options to set the search path. " +
325                    "Use configure --without-ssl to disable this message.")
326       else:
327         conf.fatal("Could not autodetect OpenSSL support. " +
328                    "Make sure OpenSSL development packages are installed. " +
329                    "Use configure --without-ssl to disable this message.")
330   else:
331     Options.options.use_openssl = conf.env["USE_OPENSSL"] = False
332
333   conf.check(lib='util', libpath=['/usr/lib', '/usr/local/lib'],
334              uselib_store='UTIL')
335
336   # normalize DEST_CPU from --dest-cpu, DEST_CPU or built-in value
337   if Options.options.dest_cpu and Options.options.dest_cpu:
338     conf.env['DEST_CPU'] = canonical_cpu_type(Options.options.dest_cpu)
339   elif 'DEST_CPU' in os.environ and os.environ['DEST_CPU']:
340     conf.env['DEST_CPU'] = canonical_cpu_type(os.environ['DEST_CPU'])
341   elif 'DEST_CPU' in conf.env and conf.env['DEST_CPU']:
342     conf.env['DEST_CPU'] = canonical_cpu_type(conf.env['DEST_CPU'])
343
344   have_librt = conf.check(lib='rt', uselib_store='RT')
345
346   have_monotonic = False
347   if have_librt:
348     code =  """
349       #include <time.h>
350       int main(void) {
351         struct timespec now;
352         clock_gettime(CLOCK_MONOTONIC, &now);
353         return 0;
354       }
355     """
356     have_monotonic = conf.check_cc(lib="rt", msg="Checking for CLOCK_MONOTONIC", fragment=code)
357
358   if have_monotonic:
359     conf.env.append_value('CPPFLAGS', '-DHAVE_MONOTONIC_CLOCK=1')
360   else:
361     conf.env.append_value('CPPFLAGS', '-DHAVE_MONOTONIC_CLOCK=0')
362
363   if sys.platform.startswith("sunos"):
364     if not conf.check(lib='socket', uselib_store="SOCKET"):
365       conf.fatal("Cannot find socket library")
366     if not conf.check(lib='nsl', uselib_store="NSL"):
367       conf.fatal("Cannot find nsl library")
368     if not conf.check(lib='kstat', uselib_store="KSTAT"):
369       conf.fatal("Cannot find kstat library")
370
371   conf.sub_config('deps/libeio')
372
373   if conf.env['USE_SHARED_V8']:
374     v8_includes = [];
375     if o.shared_v8_includes: v8_includes.append(o.shared_v8_includes);
376
377     v8_libpath = [];
378     if o.shared_v8_libpath: v8_libpath.append(o.shared_v8_libpath);
379
380     if not o.shared_v8_libname: o.shared_v8_libname = 'v8'
381
382     if not conf.check_cxx(lib=o.shared_v8_libname, header_name='v8.h',
383                           uselib_store='V8',
384                           includes=v8_includes,
385                           libpath=v8_libpath):
386       conf.fatal("Cannot find v8")
387
388     if o.debug:
389       if not conf.check_cxx(lib=o.shared_v8_libname + '_g', header_name='v8.h',
390                             uselib_store='V8_G',
391                             includes=v8_includes,
392                             libpath=v8_libpath):
393         conf.fatal("Cannot find v8_g")
394
395   if sys.platform.startswith("win32"):
396     # On win32 CARES is always static, so we can call internal functions like ares_inet_pton et al. 
397     # CARES_STATICLIB must be defined or gcc will try to make DLL stub calls
398     conf.env.append_value('CPPFLAGS', '-DCARES_STATICLIB=1')
399     conf.sub_config('deps/c-ares')
400   elif conf.env['USE_SHARED_CARES']:
401     cares_includes = [];
402     if o.shared_cares_includes: cares_includes.append(o.shared_cares_includes);
403     cares_libpath = [];
404     if o.shared_cares_libpath: cares_libpath.append(o.shared_cares_libpath);
405     if not conf.check_cxx(lib='cares',
406                           header_name='ares.h',
407                           uselib_store='CARES',
408                           includes=cares_includes,
409                           libpath=cares_libpath):
410       conf.fatal("Cannot find c-ares")
411   else:
412     conf.sub_config('deps/c-ares')
413
414
415   if conf.env['USE_SHARED_LIBEV']:
416     libev_includes = [];
417     if o.shared_libev_includes: libev_includes.append(o.shared_libev_includes);
418     libev_libpath = [];
419     if o.shared_libev_libpath: libev_libpath.append(o.shared_libev_libpath);
420     if not conf.check_cxx(lib='ev', header_name='ev.h',
421                           uselib_store='EV',
422                           includes=libev_includes,
423                           libpath=libev_libpath):
424       conf.fatal("Cannot find libev")
425   else:
426     conf.sub_config('deps/libev')
427
428
429
430   conf.define("HAVE_CONFIG_H", 1)
431
432   if sys.platform.startswith("sunos"):
433     conf.env.append_value ('CCFLAGS', '-threads')
434     conf.env.append_value ('CXXFLAGS', '-threads')
435     #conf.env.append_value ('LINKFLAGS', ' -threads')
436   elif not sys.platform.startswith("cygwin") and not sys.platform.startswith("win32"):
437     threadflags='-pthread'
438     conf.env.append_value ('CCFLAGS', threadflags)
439     conf.env.append_value ('CXXFLAGS', threadflags)
440     conf.env.append_value ('LINKFLAGS', threadflags)
441   if sys.platform.startswith("darwin"):
442     # used by platform_darwin_*.cc
443     conf.env.append_value('LINKFLAGS', ['-framework','Carbon'])
444     # cross compile for architecture specified by DEST_CPU
445     if 'DEST_CPU' in conf.env:
446       arch = conf.env['DEST_CPU']
447       # map supported_archs to GCC names:
448       arch_mappings = {'ia32': 'i386', 'x64': 'x86_64'}
449       if arch in arch_mappings:
450         arch = arch_mappings[arch]
451       flags = ['-arch', arch]
452       conf.env.append_value('CCFLAGS', flags)
453       conf.env.append_value('CXXFLAGS', flags)
454       conf.env.append_value('LINKFLAGS', flags)
455   if 'DEST_CPU' in conf.env:
456     arch = conf.env['DEST_CPU']
457     # TODO: -m32 is only available on 64 bit machines, so check host type
458     flags = None
459     if arch == 'ia32':
460       flags = '-m32'
461     if flags:
462       conf.env.append_value('CCFLAGS', flags)
463       conf.env.append_value('CXXFLAGS', flags)
464       conf.env.append_value('LINKFLAGS', flags)
465
466   # Needed for getaddrinfo in libeio
467   conf.env.append_value("CPPFLAGS", "-DX_STACKSIZE=%d" % (1024*64))
468   # LFS
469   conf.env.append_value('CPPFLAGS',  '-D_LARGEFILE_SOURCE')
470   conf.env.append_value('CPPFLAGS',  '-D_FILE_OFFSET_BITS=64')
471   conf.env.append_value('CPPFLAGS',  '-DEV_MULTIPLICITY=0')
472
473   # Makes select on windows support more than 64 FDs
474   if sys.platform.startswith("win32"):
475     conf.env.append_value('CPPFLAGS', '-DFD_SETSIZE=1024');
476
477   ## needed for node_file.cc fdatasync
478   ## Strangely on OSX 10.6 the g++ doesn't see fdatasync but gcc does?
479   code =  """
480     #include <unistd.h>
481     int main(void)
482     {
483        int fd = 0;
484        fdatasync (fd);
485        return 0;
486     }
487   """
488   if conf.check_cxx(msg="Checking for fdatasync(2) with c++", fragment=code):
489     conf.env.append_value('CPPFLAGS', '-DHAVE_FDATASYNC=1')
490   else:
491     conf.env.append_value('CPPFLAGS', '-DHAVE_FDATASYNC=0')
492
493   # arch
494   conf.env.append_value('CPPFLAGS', '-DARCH="' + conf.env['DEST_CPU'] + '"')
495
496   # platform
497   conf.env.append_value('CPPFLAGS', '-DPLATFORM="' + conf.env['DEST_OS'] + '"')
498
499   # posix?
500   if not sys.platform.startswith('win'):
501     conf.env.append_value('CPPFLAGS', '-D__POSIX__=1')
502
503   platform_file = "src/platform_%s.cc" % conf.env['DEST_OS']
504   if os.path.exists(join(cwd, platform_file)):
505     Options.options.platform_file = True
506     conf.env["PLATFORM_FILE"] = platform_file
507   else:
508     Options.options.platform_file = False
509     conf.env["PLATFORM_FILE"] = "src/platform_none.cc"
510
511   if conf.env['USE_PROFILING'] == True:
512     conf.env.append_value('CPPFLAGS', '-pg')
513     conf.env.append_value('LINKFLAGS', '-pg')
514
515   if sys.platform.startswith("win32"):
516     conf.env.append_value('LIB', 'ws2_32')
517     conf.env.append_value('LIB', 'winmm')
518
519   conf.env.append_value('CPPFLAGS', '-Wno-unused-parameter');
520   conf.env.append_value('CPPFLAGS', '-D_FORTIFY_SOURCE=2');
521
522   # Split off debug variant before adding variant specific defines
523   debug_env = conf.env.copy()
524   conf.set_env_name('debug', debug_env)
525
526   if (sys.platform.startswith("win32")):
527     # Static pthread - crashes
528     #conf.env.append_value('LINKFLAGS', '../deps/pthreads-w32/libpthreadGC2.a')
529     #debug_env.append_value('LINKFLAGS', '../deps/pthreads-w32/libpthreadGC2d.a')
530     # Pthread dll
531     conf.env.append_value('LIB', 'pthread.dll')
532
533   # Configure debug variant
534   conf.setenv('debug')
535   debug_env.set_variant('debug')
536   debug_env.append_value('CPPFLAGS', '-DDEBUG')
537   debug_compile_flags = ['-g', '-O0', '-Wall', '-Wextra']
538   debug_env.append_value('CCFLAGS', debug_compile_flags)
539   debug_env.append_value('CXXFLAGS', debug_compile_flags)
540   conf.write_config_header("config.h")
541
542   # Configure default variant
543   conf.setenv('default')
544   default_compile_flags = ['-g', '-O3']
545   conf.env.append_value('CCFLAGS', default_compile_flags)
546   conf.env.append_value('CXXFLAGS', default_compile_flags)
547   conf.write_config_header("config.h")
548
549
550 def v8_cmd(bld, variant):
551   scons = join(cwd, 'tools/scons/scons.py')
552   deps_src = join(bld.path.abspath(),"deps")
553   v8dir_src = join(deps_src,"v8")
554
555   # NOTE: We want to compile V8 to export its symbols. I.E. Do not want
556   # -fvisibility=hidden. When using dlopen() it seems that the loaded DSO
557   # cannot see symbols in the executable which are hidden, even if the
558   # executable is statically linked together...
559
560   # XXX Change this when v8 defaults x86_64 to native builds
561   # Possible values are (arm, ia32, x64, mips).
562   arch = ""
563   if bld.env['DEST_CPU']:
564     arch = "arch="+bld.env['DEST_CPU']
565
566   toolchain = "gcc"
567
568   if variant == "default":
569     mode = "release"
570   else:
571     mode = "debug"
572
573   if bld.env["SNAPSHOT_V8"]:
574     snapshot = "snapshot=on"
575   else:
576     snapshot = ""
577
578   cmd_R = sys.executable + ' "%s" -j %d -C "%s" -Y "%s" visibility=default mode=%s %s toolchain=%s library=static %s'
579
580   cmd = cmd_R % ( scons
581                 , Options.options.jobs
582                 , safe_path(bld.srcnode.abspath(bld.env_of_name(variant)))
583                 , safe_path(v8dir_src)
584                 , mode
585                 , arch
586                 , toolchain
587                 , snapshot
588                 )
589
590   if bld.env["USE_GDBJIT"]:
591     cmd += ' gdbjit=on '
592
593   if sys.platform.startswith("sunos"):
594     cmd += ' toolchain=gcc strictaliasing=off'
595
596
597
598   return ("echo '%s' && " % cmd) + cmd
599
600
601 def build_v8(bld):
602   v8 = bld.new_task_gen(
603     source        = 'deps/v8/SConstruct '
604                     + bld.path.ant_glob('v8/include/*')
605                     + bld.path.ant_glob('v8/src/*'),
606     target        = bld.env["staticlib_PATTERN"] % "v8",
607     rule          = v8_cmd(bld, "default"),
608     before        = "cxx",
609     install_path  = None)
610   v8.uselib = "EXECINFO"
611   bld.env["CPPPATH_V8"] = "deps/v8/include"
612   t = join(bld.srcnode.abspath(bld.env_of_name("default")), v8.target)
613   bld.env_of_name('default').append_value("LINKFLAGS_V8", t)
614
615
616   ### v8 debug
617   if bld.env["USE_DEBUG"]:
618     v8_debug = v8.clone("debug")
619     v8_debug.rule   = v8_cmd(bld, "debug")
620     v8_debug.target = bld.env["staticlib_PATTERN"] % "v8_g"
621     v8_debug.uselib = "EXECINFO"
622     bld.env["CPPPATH_V8_G"] = "deps/v8/include"
623     t = join(bld.srcnode.abspath(bld.env_of_name("debug")), v8_debug.target)
624     bld.env_of_name('debug').append_value("LINKFLAGS_V8_G", t)
625
626   bld.install_files('${PREFIX}/include/node/', 'deps/v8/include/*.h')
627
628
629 def build(bld):
630   ## This snippet is to show full commands as WAF executes
631   import Build
632   old = Build.BuildContext.exec_command
633   def exec_command(self, cmd, **kw):
634     if isinstance(cmd, list): print(" ".join(cmd))
635     return old(self, cmd, **kw)
636   Build.BuildContext.exec_command = exec_command
637
638   Options.options.jobs=jobs
639   product_type = Options.options.product_type
640   product_type_is_lib = product_type != 'program'
641
642   print "DEST_OS: " + bld.env['DEST_OS']
643   print "DEST_CPU: " + bld.env['DEST_CPU']
644   print "Parallel Jobs: " + str(Options.options.jobs)
645   print "Product type: " + product_type
646
647   bld.add_subdirs('deps/libeio')
648
649   if not bld.env['USE_SHARED_V8']: build_v8(bld)
650   if not bld.env['USE_SHARED_LIBEV']: bld.add_subdirs('deps/libev')
651   if not bld.env['USE_SHARED_CARES']: bld.add_subdirs('deps/c-ares')
652
653
654   ### http_parser
655   http_parser = bld.new_task_gen("cc")
656   http_parser.source = "deps/http_parser/http_parser.c"
657   http_parser.includes = "deps/http_parser/"
658   http_parser.name = "http_parser"
659   http_parser.target = "http_parser"
660   http_parser.install_path = None
661   if bld.env["USE_DEBUG"]:
662     http_parser.clone("debug")
663   if product_type_is_lib:
664     http_parser.ccflags = '-fPIC'
665
666   ### src/native.cc
667   def make_macros(loc, content):
668     f = open(loc, 'a')
669     f.write(content)
670     f.close
671
672   macros_loc_debug   = join(
673      bld.srcnode.abspath(bld.env_of_name("debug")),
674      "macros.py"
675   )
676
677   macros_loc_default = join(
678     bld.srcnode.abspath(bld.env_of_name("default")),
679     "macros.py"
680   )
681
682   ### We need to truncate the macros.py file
683   f = open(macros_loc_debug, 'w')
684   f.close
685   f = open(macros_loc_default, 'w')
686   f.close
687
688   make_macros(macros_loc_debug, "")  # leave debug(x) as is in debug build
689   # replace debug(x) with nothing in release build
690   make_macros(macros_loc_default, "macro debug(x) = ;\n")
691   make_macros(macros_loc_default, "macro assert(x) = ;\n")
692
693   if not bld.env["USE_DTRACE"]:
694     probes = [
695       'DTRACE_HTTP_CLIENT_REQUEST',
696       'DTRACE_HTTP_CLIENT_RESPONSE',
697       'DTRACE_HTTP_SERVER_REQUEST',
698       'DTRACE_HTTP_SERVER_RESPONSE',
699       'DTRACE_NET_SERVER_CONNECTION',
700       'DTRACE_NET_STREAM_END',
701       'DTRACE_NET_SOCKET_READ',
702       'DTRACE_NET_SOCKET_WRITE'
703     ]
704
705     for probe in probes:
706       make_macros(macros_loc_default, "macro %s(x) = ;\n" % probe)
707       make_macros(macros_loc_debug, "macro %s(x) = ;\n" % probe)
708
709   def javascript_in_c(task):
710     env = task.env
711     source = map(lambda x: x.srcpath(env), task.inputs)
712     targets = map(lambda x: x.srcpath(env), task.outputs)
713     source.append(macros_loc_default)
714     js2c.JS2C(source, targets)
715
716   def javascript_in_c_debug(task):
717     env = task.env
718     source = map(lambda x: x.srcpath(env), task.inputs)
719     targets = map(lambda x: x.srcpath(env), task.outputs)
720     source.append(macros_loc_debug)
721     js2c.JS2C(source, targets)
722
723   native_cc = bld.new_task_gen(
724     source='src/node.js ' + bld.path.ant_glob('lib/*.js'),
725     target="src/node_natives.h",
726     before="cxx",
727     install_path=None
728   )
729
730   # Add the rule /after/ cloning the debug
731   # This is a work around for an error had in python 2.4.3 (I'll paste the
732   # error that was had into the git commit meessage. git-blame to find out
733   # where.)
734   if bld.env["USE_DEBUG"]:
735     native_cc_debug = native_cc.clone("debug")
736     native_cc_debug.rule = javascript_in_c_debug
737
738   native_cc.rule = javascript_in_c_debug
739
740   if bld.env["USE_DTRACE"]:
741     dtrace = bld.new_task_gen(
742       name   = "dtrace",
743       source = "src/node_provider.d",
744       target = "src/node_provider.h",
745       rule   = "%s -x nolibs -h -o ${TGT} -s ${SRC}" % (bld.env.DTRACE),
746       before = "cxx",
747     )
748
749     if bld.env["USE_DEBUG"]:
750       dtrace_g = dtrace.clone("debug")
751
752     bld.install_files('${LIBDIR}/dtrace', 'src/node.d')
753
754     if sys.platform.startswith("sunos"):
755       #
756       # The USDT DTrace provider works slightly differently on Solaris than on
757       # the Mac; on Solaris, any objects that have USDT DTrace probes must be
758       # post-processed with the DTrace command.  (This is not true on the
759       # Mac, which has first-class linker support for USDT probes.)  On
760       # Solaris, we must therefore post-process our object files.  Waf doesn't
761       # seem to really have a notion for this, so we inject a task after
762       # compiling and before linking, and then find all of the node object
763       # files and shuck them off to dtrace (which will modify them in place
764       # as appropriate).
765       #
766       def dtrace_postprocess(task):
767         abspath = bld.srcnode.abspath(bld.env_of_name(task.env.variant()))
768         objs = glob.glob(abspath + 'src/*.o')
769         source = task.inputs[0].srcpath(task.env)
770         target = task.outputs[0].srcpath(task.env)
771         cmd = '%s -G -x nolibs -s %s -o %s %s' % (task.env.DTRACE,
772                                                   source,
773                                                   target,
774                                                   ' '.join(objs))
775         Utils.exec_command(cmd)
776
777       dtracepost = bld.new_task_gen(
778         name   = "dtrace-postprocess",
779         source = "src/node_provider.d",
780         target = "node_provider.o",
781         always = True,
782         before = "cxx_link",
783         after  = "cxx",
784         rule = dtrace_postprocess
785       )
786
787       t = join(bld.srcnode.abspath(bld.env_of_name("default")), dtracepost.target)
788       bld.env_of_name('default').append_value('LINKFLAGS', t)
789
790       #
791       # Note that for the same (mysterious) issue outlined above with respect
792       # to assigning the rule to native_cc/native_cc_debug, we must apply the
793       # rule to dtracepost/dtracepost_g only after they have been cloned.  We
794       # also must put node_provider.o on the link line, but because we
795       # (apparently?) lack LINKFLAGS in debug, we (shamelessly) stowaway on
796       # LINKFLAGS_V8_G.
797       #
798       if bld.env["USE_DEBUG"]:
799         dtracepost_g = dtracepost.clone("debug")
800         dtracepost_g.rule = dtrace_postprocess
801         t = join(bld.srcnode.abspath(bld.env_of_name("debug")), dtracepost.target)
802         bld.env_of_name("debug").append_value('LINKFLAGS_V8_G', t)
803
804
805   ### node lib
806   node = bld.new_task_gen("cxx", product_type)
807   node.name         = "node"
808   node.target       = "node"
809   node.uselib = 'RT EV OPENSSL CARES EXECINFO DL KVM SOCKET NSL KSTAT UTIL OPROFILE'
810   node.add_objects = 'eio http_parser'
811   if product_type_is_lib:
812     node.install_path = '${LIBDIR}'
813   else:
814     node.install_path = '${PREFIX}/bin'
815   node.chmod = 0755
816   node.source = """
817     src/node.cc
818     src/node_buffer.cc
819     src/node_javascript.cc
820     src/node_extensions.cc
821     src/node_http_parser.cc
822     src/node_net.cc
823     src/node_io_watcher.cc
824     src/node_constants.cc
825     src/node_cares.cc
826     src/node_events.cc
827     src/node_file.cc
828     src/node_signal_watcher.cc
829     src/node_stat_watcher.cc
830     src/node_timer.cc
831     src/node_script.cc
832     src/node_os.cc
833     src/node_dtrace.cc
834     src/node_string.cc
835   """
836
837   if sys.platform.startswith("win32"):
838     node.source += " src/node_stdio_win32.cc "
839     node.source += " src/node_child_process_win32.cc "
840   else:
841     node.source += " src/node_stdio.cc "
842     node.source += " src/node_child_process.cc "
843
844   node.source += bld.env["PLATFORM_FILE"]
845   if not product_type_is_lib:
846     node.source = 'src/node_main.cc '+node.source
847
848   if bld.env["USE_OPENSSL"]: node.source += " src/node_crypto.cc "
849
850   node.includes = """
851     src/
852     deps/libeio
853     deps/http_parser
854   """
855
856   if not bld.env["USE_SHARED_V8"]: node.includes += ' deps/v8/include '
857
858   if not bld.env["USE_SHARED_LIBEV"]:
859     node.add_objects += ' ev '
860     node.includes += ' deps/libev '
861
862   if not bld.env["USE_SHARED_CARES"]:
863     node.add_objects += ' cares '
864     node.includes += '  deps/c-ares deps/c-ares/' + bld.env['DEST_OS'] + '-' + bld.env['DEST_CPU']
865
866   if sys.platform.startswith('cygwin'):
867     bld.env.append_value('LINKFLAGS', '-Wl,--export-all-symbols')
868     bld.env.append_value('LINKFLAGS', '-Wl,--out-implib,default/libnode.dll.a')
869     bld.env.append_value('LINKFLAGS', '-Wl,--output-def,default/libnode.def')
870     bld.install_files('${LIBDIR}', "build/default/libnode.*")
871
872   def subflags(program):
873     x = { 'CCFLAGS'   : " ".join(program.env["CCFLAGS"]).replace('"', '\\"')
874         , 'CPPFLAGS'  : " ".join(program.env["CPPFLAGS"]).replace('"', '\\"')
875         , 'LIBFLAGS'  : " ".join(program.env["LIBFLAGS"]).replace('"', '\\"')
876         , 'PREFIX'    : safe_path(program.env["PREFIX"])
877         , 'VERSION'   : '0.4.7' # FIXME should not be hard-coded, see NODE_VERSION_STRING in src/node_version.
878         }
879     return x
880
881   # process file.pc.in -> file.pc
882
883   node_conf = bld.new_task_gen('subst', before="cxx")
884   node_conf.source = 'src/node_config.h.in'
885   node_conf.target = 'src/node_config.h'
886   node_conf.dict = subflags(node)
887   node_conf.install_path = '${PREFIX}/include/node'
888
889   if bld.env["USE_DEBUG"]:
890     node_g = node.clone("debug")
891     node_g.target = "node_g"
892     node_g.uselib += ' V8_G'
893
894     node_conf_g = node_conf.clone("debug")
895     node_conf_g.dict = subflags(node_g)
896     node_conf_g.install_path = None
897
898   # After creating the debug clone, append the V8 dep
899   node.uselib += ' V8'
900
901   bld.install_files('${PREFIX}/include/node/', """
902     config.h
903     src/node.h
904     src/node_object_wrap.h
905     src/node_buffer.h
906     src/node_events.h
907     src/node_version.h
908   """)
909
910   # Only install the man page if it exists.
911   # Do 'make doc install' to build and install it.
912   if os.path.exists('doc/node.1'):
913     bld.install_files('${PREFIX}/share/man/man1/', 'doc/node.1')
914
915   bld.install_files('${PREFIX}/bin/', 'tools/node-waf', chmod=0755)
916   bld.install_files('${LIBDIR}/node/wafadmin', 'tools/wafadmin/*.py')
917   bld.install_files('${LIBDIR}/node/wafadmin/Tools', 'tools/wafadmin/Tools/*.py')
918
919   # create a pkg-config(1) file
920   node_conf = bld.new_task_gen('subst', before="cxx")
921   node_conf.source = 'tools/nodejs.pc.in'
922   node_conf.target = 'tools/nodejs.pc'
923   node_conf.dict = subflags(node)
924
925   bld.install_files('${LIBDIR}/pkgconfig', 'tools/nodejs.pc')
926
927 def shutdown():
928   Options.options.debug
929   # HACK to get binding.node out of build directory.
930   # better way to do this?
931   if Options.commands['configure']:
932     if not Options.options.use_openssl:
933       print "WARNING WARNING WARNING"
934       print "OpenSSL not found. Will compile Node without crypto support!"
935
936     if not Options.options.platform_file:
937       print "WARNING: Platform not fully supported. Using src/platform_none.cc"
938
939   elif not Options.commands['clean']:
940     if sys.platform.startswith("win32"):
941       if os.path.exists('build/default/node.exe'):
942         os.system('cp build/default/node.exe .')
943       if os.path.exists('build/debug/node_g.exe'):
944         os.system('cp build/debug/node_g.exe .')
945     else:
946       if os.path.exists('build/default/node') and not os.path.exists('node'):
947         os.symlink('build/default/node', 'node')
948       if os.path.exists('build/debug/node_g') and not os.path.exists('node_g'):
949         os.symlink('build/debug/node_g', 'node_g')
950   else:
951     if sys.platform.startswith("win32"):
952       if os.path.exists('node.exe'): os.unlink('node.exe')
953       if os.path.exists('node_g.exe'): os.unlink('node_g.exe')
954     else:
955       if os.path.exists('node'): os.unlink('node')
956       if os.path.exists('node_g'): os.unlink('node_g')