Commit ccb55c3
Merge branch 'master' of gitorious.org:supplement/birdfont
Changed files (168)
modifiedREADMEaddedconfiguremodifiedlayout/style.cssmodifiedpo/birdfont.potmodifiedpo/de.pomodifiedpo/sv.pomodifiedwafaddedwaf-1.7.6/ChangeLogaddedwaf-1.7.6/DEVELaddedwaf-1.7.6/READMEaddedwaf-1.7.6/TODOaddedwaf-1.7.6/configureaddedwaf-1.7.6/utils/genbench.pyaddedwaf-1.7.6/utils/launcher/LICENSEaddedwaf-1.7.6/utils/launcher/README.mdaddedwaf-1.7.6/utils/launcher/waf-launcher.slnaddedwaf-1.7.6/utils/launcher/waf-launcher/AssemblyInfo.csaddedwaf-1.7.6/utils/launcher/waf-launcher/Main.csaddedwaf-1.7.6/utils/launcher/waf-launcher/waf-launcher.csprojaddedwaf-1.7.6/utils/launcher/wscriptaddedwaf-1.7.6/utils/waf.bataddedwaf-1.7.6/waf-lightaddedwaf-1.7.6/waflib/Build.pyaddedwaf-1.7.6/waflib/ConfigSet.pyaddedwaf-1.7.6/waflib/Configure.pyaddedwaf-1.7.6/waflib/Context.pyaddedwaf-1.7.6/waflib/Errors.pyaddedwaf-1.7.6/waflib/Logs.pyaddedwaf-1.7.6/waflib/Node.pyaddedwaf-1.7.6/waflib/Options.pyaddedwaf-1.7.6/waflib/Runner.pyaddedwaf-1.7.6/waflib/Scripting.pyaddedwaf-1.7.6/waflib/Task.pyaddedwaf-1.7.6/waflib/TaskGen.pyaddedwaf-1.7.6/waflib/Tools/__init__.pyaddedwaf-1.7.6/waflib/Tools/ar.pyaddedwaf-1.7.6/waflib/Tools/asm.pyaddedwaf-1.7.6/waflib/Tools/bison.pyaddedwaf-1.7.6/waflib/Tools/c.pyaddedwaf-1.7.6/waflib/Tools/c_aliases.pyaddedwaf-1.7.6/waflib/Tools/c_config.pyaddedwaf-1.7.6/waflib/Tools/c_osx.pyaddedwaf-1.7.6/waflib/Tools/c_preproc.pyaddedwaf-1.7.6/waflib/Tools/c_tests.pyaddedwaf-1.7.6/waflib/Tools/ccroot.pyaddedwaf-1.7.6/waflib/Tools/compiler_c.pyaddedwaf-1.7.6/waflib/Tools/compiler_cxx.pyaddedwaf-1.7.6/waflib/Tools/compiler_d.pyaddedwaf-1.7.6/waflib/Tools/compiler_fc.pyaddedwaf-1.7.6/waflib/Tools/cs.pyaddedwaf-1.7.6/waflib/Tools/cxx.pyaddedwaf-1.7.6/waflib/Tools/d.pyaddedwaf-1.7.6/waflib/Tools/d_config.pyaddedwaf-1.7.6/waflib/Tools/d_scan.pyaddedwaf-1.7.6/waflib/Tools/dbus.pyaddedwaf-1.7.6/waflib/Tools/dmd.pyaddedwaf-1.7.6/waflib/Tools/errcheck.pyaddedwaf-1.7.6/waflib/Tools/fc.pyaddedwaf-1.7.6/waflib/Tools/fc_config.pyaddedwaf-1.7.6/waflib/Tools/fc_scan.pyaddedwaf-1.7.6/waflib/Tools/flex.pyaddedwaf-1.7.6/waflib/Tools/g95.pyaddedwaf-1.7.6/waflib/Tools/gas.pyaddedwaf-1.7.6/waflib/Tools/gcc.pyaddedwaf-1.7.6/waflib/Tools/gdc.pyaddedwaf-1.7.6/waflib/Tools/gfortran.pyaddedwaf-1.7.6/waflib/Tools/glib2.pyaddedwaf-1.7.6/waflib/Tools/gnu_dirs.pyaddedwaf-1.7.6/waflib/Tools/gxx.pyaddedwaf-1.7.6/waflib/Tools/icc.pyaddedwaf-1.7.6/waflib/Tools/icpc.pyaddedwaf-1.7.6/waflib/Tools/ifort.pyaddedwaf-1.7.6/waflib/Tools/intltool.pyaddedwaf-1.7.6/waflib/Tools/irixcc.pyaddedwaf-1.7.6/waflib/Tools/javaw.pyaddedwaf-1.7.6/waflib/Tools/kde4.pyaddedwaf-1.7.6/waflib/Tools/ldc2.pyaddedwaf-1.7.6/waflib/Tools/lua.pyaddedwaf-1.7.6/waflib/Tools/msvc.pyaddedwaf-1.7.6/waflib/Tools/nasm.pyaddedwaf-1.7.6/waflib/Tools/perl.pyaddedwaf-1.7.6/waflib/Tools/python.pyaddedwaf-1.7.6/waflib/Tools/qt4.pyaddedwaf-1.7.6/waflib/Tools/ruby.pyaddedwaf-1.7.6/waflib/Tools/suncc.pyaddedwaf-1.7.6/waflib/Tools/suncxx.pyaddedwaf-1.7.6/waflib/Tools/tex.pyaddedwaf-1.7.6/waflib/Tools/vala.pyaddedwaf-1.7.6/waflib/Tools/waf_unit_test.pyaddedwaf-1.7.6/waflib/Tools/winres.pyaddedwaf-1.7.6/waflib/Tools/xlc.pyaddedwaf-1.7.6/waflib/Tools/xlcxx.pyaddedwaf-1.7.6/waflib/Utils.pyaddedwaf-1.7.6/waflib/__init__.pyaddedwaf-1.7.6/waflib/ansiterm.pyaddedwaf-1.7.6/waflib/extras/__init__.pyaddedwaf-1.7.6/waflib/extras/add_objects.pyaddedwaf-1.7.6/waflib/extras/batched_cc.pyaddedwaf-1.7.6/waflib/extras/biber.pyaddedwaf-1.7.6/waflib/extras/bjam.pyaddedwaf-1.7.6/waflib/extras/boo.pyaddedwaf-1.7.6/waflib/extras/boost.pyaddedwaf-1.7.6/waflib/extras/c_bgxlc.pyaddedwaf-1.7.6/waflib/extras/c_dumbpreproc.pyaddedwaf-1.7.6/waflib/extras/cabal.pyaddedwaf-1.7.6/waflib/extras/compat15.pyaddedwaf-1.7.6/waflib/extras/cython.pyaddedwaf-1.7.6/waflib/extras/dcc.pyaddedwaf-1.7.6/waflib/extras/doxygen.pyaddedwaf-1.7.6/waflib/extras/dpapi.pyaddedwaf-1.7.6/waflib/extras/dumbpreproc.pyaddedwaf-1.7.6/waflib/extras/eclipse.pyaddedwaf-1.7.6/waflib/extras/erlang.pyaddedwaf-1.7.6/waflib/extras/fc_bgxlf.pyaddedwaf-1.7.6/waflib/extras/fc_cray.pyaddedwaf-1.7.6/waflib/extras/fc_nag.pyaddedwaf-1.7.6/waflib/extras/fc_open64.pyaddedwaf-1.7.6/waflib/extras/fc_pgfortran.pyaddedwaf-1.7.6/waflib/extras/fc_solstudio.pyaddedwaf-1.7.6/waflib/extras/fc_xlf.pyaddedwaf-1.7.6/waflib/extras/fluid.pyaddedwaf-1.7.6/waflib/extras/freeimage.pyaddedwaf-1.7.6/waflib/extras/fsb.pyaddedwaf-1.7.6/waflib/extras/fsc.pyaddedwaf-1.7.6/waflib/extras/gccdeps.pyaddedwaf-1.7.6/waflib/extras/go.pyaddedwaf-1.7.6/waflib/extras/gob2.pyaddedwaf-1.7.6/waflib/extras/local_rpath.pyaddedwaf-1.7.6/waflib/extras/lru_cache.pyaddedwaf-1.7.6/waflib/extras/make.pyaddedwaf-1.7.6/waflib/extras/md5_tstamp.pyaddedwaf-1.7.6/waflib/extras/midl.pyaddedwaf-1.7.6/waflib/extras/misc.pyaddedwaf-1.7.6/waflib/extras/msvs.pyaddedwaf-1.7.6/waflib/extras/netcache_client.pyaddedwaf-1.7.6/waflib/extras/objcopy.pyaddedwaf-1.7.6/waflib/extras/ocaml.pyaddedwaf-1.7.6/waflib/extras/package.pyaddedwaf-1.7.6/waflib/extras/parallel_debug.pyaddedwaf-1.7.6/waflib/extras/pep8.pyaddedwaf-1.7.6/waflib/extras/pgicc.pyaddedwaf-1.7.6/waflib/extras/pgicxx.pyaddedwaf-1.7.6/waflib/extras/print_commands.pyaddedwaf-1.7.6/waflib/extras/proc.pyaddedwaf-1.7.6/waflib/extras/protoc.pyaddedwaf-1.7.6/waflib/extras/qnxnto.pyaddedwaf-1.7.6/waflib/extras/relocation.pyaddedwaf-1.7.6/waflib/extras/resx.pyaddedwaf-1.7.6/waflib/extras/review.pyaddedwaf-1.7.6/waflib/extras/run_do_script.pyaddedwaf-1.7.6/waflib/extras/run_m_script.pyaddedwaf-1.7.6/waflib/extras/run_py_script.pyaddedwaf-1.7.6/waflib/extras/run_r_script.pyaddedwaf-1.7.6/waflib/extras/sas.pyaddedwaf-1.7.6/waflib/extras/scala.pyaddedwaf-1.7.6/waflib/extras/slow_qt4.pyaddedwaf-1.7.6/waflib/extras/smart_continue.pyaddedwaf-1.7.6/waflib/extras/softlink_libs.pyaddedwaf-1.7.6/waflib/extras/swig.pyaddedwaf-1.7.6/waflib/extras/syms.pyaddedwaf-1.7.6/waflib/extras/sync_exec.pyaddedwaf-1.7.6/waflib/extras/ticgt.pyaddedwaf-1.7.6/waflib/extras/valadoc.pyaddedwaf-1.7.6/waflib/extras/why.pyaddedwaf-1.7.6/waflib/extras/win32_opts.pyaddedwaf-1.7.6/waflib/extras/xcode.pyaddedwaf-1.7.6/waflib/fixpy2.pyaddedwaf-1.7.6/wscript
Diff
@@ -19,7 +19,7 @@ with a -dev or -devel affix. You can run this as root if you are using Debian: sudo apt-get install valac libglib2.0-dev libgtk2.0-dev libxml2-dev libwebkitgtk-dev Configure, build and install with waf:-./waf configure+./configure ./waf build sudo ./waf install @@ -36,6 +36,7 @@ http://greg.thehellings.com/2012/02/a-better-ubuntu-mingw-experience/ You need wine and nsis windows installer as well. Compile and build the installer with:+./configure ./waf configure --win32 --installer ./waf clean ./waf build --win32 --installernew file mode 100755@@ -0,0 +1,6 @@+#!/bin/bash+cd waf-* && \+./configure && \+cp ./waf ../ && \+cd .. && \+./waf configure@@ -34,7 +34,7 @@ div.menu_item:hover { div.inner_format_box { float: left;- width: 170px;+ width: 210px; height: 200px; padding: 0 0 0 0; margin: 0 10px 0 0;@@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n"-"POT-Creation-Date: 2012-12-14 07:49+0100\n"+"POT-Creation-Date: 2012-12-14 17:51+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n"@@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n"-"POT-Creation-Date: 2012-12-14 07:49+0100\n"-"PO-Revision-Date: 2012-12-13 19:10+0000\n"+"POT-Creation-Date: 2012-12-14 17:51+0100\n"+"PO-Revision-Date: 2012-12-14 07:59+0000\n" "Last-Translator: Johan <johan.mattsson.m@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: de\n"@@ -16,7 +16,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Pootle 2.5.0-beta1\n"-"X-POOTLE-MTIME: 1355425853.0\n"+"X-POOTLE-MTIME: 1355471940.0\n" #: ../src/Argument.vala:225 msgid "Usage"@@ -28,7 +28,7 @@ msgstr "" #: ../src/Argument.vala:227 msgid "OPTION"-msgstr ""+msgstr "OPTIONEN" #: ../src/Argument.vala:229 msgid "show coordinate in glyph view"@@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n"-"POT-Creation-Date: 2012-12-14 07:49+0100\n"-"PO-Revision-Date: 2012-12-14 06:48+0000\n"+"POT-Creation-Date: 2012-12-14 17:51+0100\n"+"PO-Revision-Date: 2012-12-14 07:23+0000\n" "Last-Translator: Johan <johan.mattsson.m@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: sv\n"@@ -16,7 +16,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Pootle 2.5.0-beta1\n"-"X-POOTLE-MTIME: 1355467690.0\n"+"X-POOTLE-MTIME: 1355469825.0\n" #: ../src/Argument.vala:225 msgid "Usage"@@ -88,7 +88,7 @@ msgstr "Skriver" #: ../src/CutBackgroundTool.vala:37 msgid "Crop background image"-msgstr "Beskär bakgrundsbilden"+msgstr "Beskär bakgrundsbild" #: ../src/ExportTool.vala:29 msgid "Export glyph to svg file"Binary files a/waf and b/waf differnew file mode 100644@@ -0,0 +1,325 @@+NEW IN WAF 1.7.6+----------------+* Better encapsulation of conf.check_cfg(uselib_store=...) defines #1212+* Support for python modules in fortran+* Extension files of D binaries on Mac+* Raise an error when a tex manually-provided dependency is not found #1209+* Enforce a stable name in bld(rule=..., name=undefined) to prevent rebuilds+* Enhanced support for flex on win32 and msys #1207 #1211+* Fixed a regression on configuration tests running with -Werror/-Wall #1220++NEW IN WAF 1.7.5+----------------+* Fixed the kde4 library detection on Fedora+* New tool for protocol buffers (protoc.py) #1184+* Fixed a syntax error affecting Python < 2.6++NEW IN WAF 1.7.4+----------------+* Fixed a regression in the Node,Task and Context classes++NEW IN WAF 1.7.3+-----------------+* Fixed the LD_LIBRARY_PATH race condition in waf_unit_test #1200+* Library detection fixes in boost.py #1199+* Various waf_unit_test enhancements #1194+* Use the same function signature main(int, char**) in all configuration tests #1192+* Fixed the Clang version number detection #1191+* Let the feature 'includes' propagate INCLUDES and FRAMEWORKPATH variables+* Fix for incorrect installation paths #1202+* Cabal script (haskell)++NEW IN WAF 1.7.2+----------------+* Install bld.subst() targets+* New scanner for winrc processing #1186++NEW IN WAF 1.7.1+----------------+* Updated the exclusion regexps for "waf dist"+* Added an example in playground/nasm+* Enabled compatibility with pkgconf+* Response files for c# #1182+* Minor docstring updates #1188+* New tool for compiling .net resource files (waflib/extras/resx.py) #1183+* New tool for compiling .midl files (waflib/extras/midl.py) #1185++NEW IN WAF 1.7.0+----------------+* The compat15 tool is disabled by default (the README file explains how to enable it)+* Python >= 2.4 is now required+* Python >= 2.6 is required for creating the Waf file in the source tree+* Added Utils.writef (similar to Utils.readf)+* Added Node.evict() to provide more control over invalid references+* Do not raise exception on --help when running on python 2.4+* Node.search -> Node.search_node (consistent with make_node and find_node)+* Errors are reported on configuration test failures with execute=True #1111+* Added header prefixing (autoconf-like) #1117+* Removed the warnings on "waf install" #1120+* Extended bld.subst() to perform simple copies to the build directory+* Removed the default DLL_EXPORT define on gcc/g++ shared libraries+* Calling ctx.root.ant_glob(abspath) will now return results #1135+* New case-insentive option for ant_glob #1148+* Ported demos/asm to 64-bit, forcing gcc over as+* Updated the gccdeps tool #1162+* Improved the C# processing #1154, #1153+* Removed the empty flags from LIB/INCLUDE in the msvc configuration #1159+* Added an 'encoding' parameter to bld.subst()+* Detect Visual Studio 2011 beta+* Detect cython dependencies of the form "from module import x" #1044+* Use the cython includes in the dependency scanner #1166+* Improved the behaviour of Utils.readf/Utils.writef on Win32+* Made Task.__repr__ more robust #1174+* Fixed the gcc builds on hp-ux+* Let gccdeps work with other compilers #1179++NEW IN WAF 1.6.11+-----------------+* Enable custom variables for the boost detection #1089+* Disable the config test execution when detecting boost #1090+* Process moc classes in .cpp files by default #1095+* Apply the chmod attribute to the versioned libraries (vnum) #1097+* Fixed the python detection on OSX #1098+* Changed the win32 color settings for Windows 7 #1099+* Set the default fortran linker for ifort to xiar #1104++NEW IN WAF 1.6.10+-----------------+* Fixed the 'remove' attribute propagation in ant_glob #1086+* Fixed the behavior of recurse(name=xyz) when looking in existing folders+* Fixed a problem with include paths in the relocation tool #1078+* Improved the pgicc compiler detection #1080+* Fixed the behavior of 'waf options' #1076+* Process larger java projects #1074+* Remove the ':' from the drives when dealing with foreign files and folders on Win32+* Let the 'subst' feature process a chmod attribute+* Added a hook for distutils variable query #1083++NEW IN WAF 1.6.9+----------------+* Fixed the duplicate moc file creation in slow_qt4 #1047+* Fixed the Visual Studio 2008 projects creation #1033+* Added a workaround to avoid creating include folders not under the build directory #1049+* Added a default virtual folder structure for out-of-tree build files #1053+* Added a way to set variants containing /, for example linux/debug+* Added a more intuitive behaviour for conf.setenv() #1062+* Fixed the multiple bibliography processing for tex #1040+* Windows CE detection improvements #1065+* Fixed the library installation on OSX+* Fixed the Powerpc/IPhone platform detection+* Added an Xcode project generator++NEW IN WAF 1.6.8+----------------+* Fixed a typo in Utils.py affecting Win32 platforms (copystat) #1029+* Fixed a minor bug in the Eclipse project generator+* Fixed a typo that prevented Waf from running on Pypy-trunk+* Make the xlc/xlc++ compiler detection more accurate by looking at the version number #1022+* Minor perl, python and ruby tool improvements+* Better logs for the boost detection #1036+* Fixed a performance issue in Runner.py #1039+* Changed the position of the linker flags #1025++NEW IN WAF 1.6.7+----------------++* Provide more diagnostic for invalid build groups #914+* Various enhancements to msvs.py+* Read MSVC_VERSIONS and MSVC_TARGETS from the command-line+* Minor cross-compiler detection fix on msvc.py+* Fix the redirections with pipes (waf configure > log)+* Do not display runnable_status exceptions when running with -k+* Let -k stop at the first runnable_status error and -kk run even further+* Merge the add_object extension in the main line (source='file.o')+* Make update_outputs more robust with changes in the task definition #1017+* Qt4 detection on Win32++NEW IN WAF 1.6.6+----------------++* Fix the performance regression related to #974++NEW IN WAF 1.6.5+----------------++* More documentation+* Re-enable the colors for msys+* Add the .ui files for the qt4 translations+* Fix the conf.check_large_file() test+* Fix the conf.check_library() in C++ mode #955+* Improve the latex scanner to avoid depending on generated files #943+* Remove the @file processing from the winrc tasks+* Fix the python detection using python-config+* Add the missing default includes and defines to the moc command+* Improve support for hierarchical go-lang packages #953+* Fix the gfortran verbose flag detection on Windows+* Fix the support of fortran import libraries #950+* Added a fix for running with Python 2.4 on Windows #949+* Limited support for IronPython+* Support for older Visual Studio versions (VC6) #952+* New waf.bat file #964+* New method ConfigSet.keys+* New Visual Studio and Eclipse CTD project generators (waflib/extras)+* New lru_cache tool for use with WAFCACHE (waflib/extras)++NEW IN WAF 1.6.4+----------------++* Fix the Python detection on win32 #883+* Optimize the Python file installation #892+* Force +x permissions on installed fortran programs #893+* Qt library detection fixes #895+* Ensure that unit tests are executed only after the symlinks are created+* Fix the precedence constraints for classes ending in _task #896+* Support the install_path attribute with add_pcfile #913+* Make the goprograms executable when installed #928+* Allow non-python data files in the waf executable #927+* Enforce a build order based on the scanner results #777, #922+* Multiple msvc detection fixes #907 #910 #923 #924 #926+* Fix the -of flag append with dmd #917+* Boost detection fixes #920+* Support newer javac compilers #921+* Fix the execution on python 2.3 for: "waf update", msvc.py, fc.py+* Improve the support for mac applications (demos/mac_app)+* Better default regexps in "waf step"+* New error check for tasks creating the same nodes or having the same identifiers (waf -v)+* New variables conf.env.NO_LOCK_IN_TOP/OUT/RUN for special projects (top='..')+* New example on avoiding rebuilds when moving a project (playground/relocate)+* Improve go-lang support for cgo-packages (fixes #932)+* Fix the progress bar on cmd and msys++NEW IN WAF 1.6.3+----------------++* Fixed the interaction of Fortran configuration tests and WAFCACHE #842+* Various documentation fixes+* Set the PYTHONARCHDIR variable for installing python extensions+* Fixed the Waf file creation with --zip-type=gz (bunzip2 was not replaced by gzip -d)+* Fixed multiple problems in the call to TaskGen.declare_chain(...) #850+* Fixed the task attribute 'vars' which might cause unnecessary rebuilds #852+* Return the value of post_check(...) in conf.check(...) #857+* Rewrite the boost tool (waflib/extras/boost.py) #814, #454, #424+* More fortran file extensions: .for, .FOR #867+* Searching above the root nodes no longer raise exceptions #868+* Msvc detection fixes for non-utf8 encodings #873+* Fixed the destdir processing on Windows #874+* Stop changing the flags on waf -v (make the errors more visible) #875+* Fixed the resource file compilation on Windows #876+* Fixed the vala file installation #881+* New system of plugins for C/C++/Fortran compilers (files named c_* in waflib/extras/)+* New examples of interaction between Waf and existing makefiles (playground/)+* New names for @before/@after: @before_method/@after_method++NEW IN WAF 1.6.2+----------------++* Support for C# debugging files #797+* Add -relocation-model=pic for shared libraries on ldc+* Fixed 'waf dist' for tar files on python 3 #799+* Make the latex scanner recursive #798+* Enable the packing of non-python files in the waf file #802+* Improve the feature sniffing for hybrid programs/libraries #800+* New apidocs + tutorial in Sphinx format+* Add the CPPFLAGS from os.environ #803+* Create the java output directory anywhere #806+* Enable the .luac file installation+* Process Qt translation files+* Detect when the folders were copied and prompt for "waf configure"+* Parse_flags for the *-config outputs on windows (backslashes) #811+* Fix the doxygen task build order + improve the dependency scanner #821+* Various msvc fixes #819, #826, #825+* Ported the batch executor to waf 1.6 (batched_cc)+* New tools: erlang, scala+* Moved conf.multicheck(..) from playground to the library+* New parameter to avoid reading the same scripts: bld.recurse(dir, once=True)+* Detect invalid method calls in 'waf -v' such as env.append/env.add/env.prepend+* New manifest option for jar targets #832++NEW IN WAF 1.6.1+----------------++* Fixed the method check_waf_version #764+* Fixed the name in ctx.recurse(name) #769+* Stop caching the install tasks and tasks that have no outputs #770+* Fix the log in Context.cmd_and_log() when calling with "quiet" #778+* c_preproc exception when a file has the same name as a directory #777+* 'intltool_po' does not install the .mo files #782+* 'intltool_in' was broken #792+* Bind stderr and stdout to the exception in Context.cmd_and_log #779+* Tasks not rebuilding properly when the 'run' method changes #786+* Print the progress bar information as late as possible #787+* Fix for the FRAMEWORK value processing+* Verbose mode should not require the compat15 tools #790+* Let static libraries use other static libraries as in 1.5 #768+* Fix for the boost tool #776+* boost tool update (in playground) #780+* Updated the java tool and examples+* New gcj tool in playground+* Update the c# tool and examples (playground) #796+* Read external c# libraries #774+* Xelatex support #785+* Rebuild fortran files when .mod files change #766+* docs #781+* Improve the ant_glob behaviour on ctx.root + absolute paths+* Fix for glib_mkenums and dbus-binding-tool #795+* New feature 'subst' (see demos/subst)++NEW IN WAF 1.6.0+----------------++General:+* Python 3 syntax by default (runs unmodified for 2.6, 2.7, 3.0 and 3.1)+* Environment -> ConfigSet+* only lists are allowed in ConfigSet+* Better Node apis+* Utils.load_tool -> Context.load_tool+* set_options becomes options+* only the build-related commands require a configured project+* new variant system + build context commands+* removed the pseudo glob in installation methods+* eliminate find_sources_in_dirs+* node.__class__.bld → node.ctx+* bld.new_task_gen(...) disappears, use bld(...)+* network updates for waf tools+* accept node objects in the source and includes attributes+* remove task_gen.allnodes: modify self.source directly+* merge the include system for c, c++, d, gas and nasm+* allow top == out (no build directory)+* merge the Tool/wscript system (detect->configure, set_options->options)+* new command "waf list" to list the x for "waf build --targets=x"+* rename apply_core -> process_source+* rename apply_rule -> process_rule+* rename Task.TaskBase.classes -> Task.classes+* the modules Utils.py and Logs.py are now independent from the rest of waf (imports)+* remove Task.TaskManager and Build.BuildContext.all_task_gen to improve the build group handling+* remove program_USELIB, shlib_USELIB staticlib_USELIB support+* use tasks for target installation+* improve the exception handling (WscriptError was removed, use WafError)+* let the commands access node objects+* infer the build directory from the lock filename+* waf step --file=main.c+* post task generators in a lazy manner++preview 3:+* remove the /W3 flag from msvc default flags+* opt.tool_options -> opt.load (now all commands inherit the 'tool' method)+* conf.check_tool -> conf.load+* do not copy files when creating tar files in 'waf dist'+* add zip files in 'waf dist'+* fix the behaviour of 'waf distcheck'+* preprocessor optimizations+* python 2 fixes++release candidate:+* cache fixes+* fortran fixes+* python 2 and 3 fixes+* docs and docstrings+* support for custom waf files and preludes+* fix in waflib.Context for overriding command classes+* port the doxygen tool+* Utils.to_hashtable -> Utils.str2dict+* change the thread pool to enable thread pool sharing+* fixed a regression on win32 + ansiterm.py + python 3 -> thanks to kesselhaus :-)+* various msvc fixes (thanks to Nicolas Mercier)+new file mode 100644@@ -0,0 +1,46 @@+Main repository for waf 1.7 on http://waf.googlecode.com/git/+-------------------------------------------------------------++waflib the core library+waflib/Tools essential waf tools+waflib/extras contributed tools which are not included in the+ waf file by default (except "compat15")+build_system_kit examples of build systems that can be created from waf+tests various unit tests, most are unused anymore+playground experiments and integration tests for the tools in+ the folder waflib/extras+demos integration tests - the folder can be configured+ as a standalone project+demos/* integration tests and examples used as documentation+docs documentation+docs/sphinx project extracting the docstrings from the source code to+ create the apidocs++Documentation repository on http://docs.waf.googlecode.com/git/+---------------------------------------------------------------++Contains the documentation:+API documentation http://docs.waf.googlecode.com/git/apidocs_17/index.html+The Waf Book http://docs.waf.googlecode.com/git/book_17/single.html+The Waf Book for Waf 1.6 (deprecated) http://docs.waf.googlecode.com/git/book_16/single.html+The Waf Book for Waf 1.5 (deprecated) http://docs.waf.googlecode.com/git/book_15/single.html++Programming details+-------------------++* Do not use x.split("\n") but x.splitlines()+* Do not catch all exceptions unless you have a good reason to do so+* File handles are too easy to get wrong, use Node.readf/Node.writef/Utils.readf/Utils.writef++Wiki documentation on http://wiki.waf.googlecode.com/git/+---------------------------------------------------------++...++Previous branches+-----------------++old svn repository http://waf.googlecode.com/svn/trunk/ (for waf 1.5, read-only and unused)+old branch for waf 1.5 http://waf.googlecode.com/svn/branches/waf-1.5/ (again, read-only and unused)++new file mode 100644@@ -0,0 +1,50 @@+WHAT YOU WILL FIND HERE+-----------------------++Waf (1.7)++For the manual: http://docs.waf.googlecode.com/git/book_16/single.html+For the api docs: http://docs.waf.googlecode.com/git/apidocs_16/index.html+For the examples: see the folder demos/++HOW TO CREATE THE WAF SCRIPT+----------------------------++Python 2.6, 2.7, 3.0, 3.1 or 3.2 is required to generate the waf script. Execute:+$ ./waf-light configure build+Or, if you have several python versions installed:+$ python3 ./waf-light configure build++The Waf tools in waflib/extras are not added to the waf script. To add+some of them, use the --tools switch:+$ ./waf-light --tools=compat15,swig++To add a tool that does not exist in the folder extras, pass an absolute path, and+to customize the initialization, pass the parameter 'prelude'. Here is for example+how to create a waf file using the compat15 module:+$ ./waf-light --tools=compat15 --prelude=$'\tfrom waflib.extras import compat15\n'++Any kind of initialization is possible, though one may prefer the build system kit (folder build_system_kit):+$ ./waf-light --make-waf --tools=compat15,/comp/waf/aba.py --prelude=$'\tfrom waflib.extras import compat15\n\tprint "ok"'++HOW TO TRY THE EXAMPLES+-----------------------++Try this:+$ cp waf demos/c/+$ cd demos/c/+$ ./waf configure build++USING GIT+---------++$ git clone https://code.google.com/p/waf/+set $HOME/.netrc to read:+machine code.google.com login user@gmail.com password pass+$ git remote add code https://code.google.com/p/waf.docs/+... make a few changes+$ git push code++---------------------------+Thomas Nagy, 2012 (ita)+new file mode 100644@@ -0,0 +1,22 @@+Waf 1.7.x+---------++* fix the remaining bugs+* provide more extensions+++Can be useful:++def bld_command(*k):+ fun = k[0]+ name = fun.__name__+ from waflib.Build import BuildContext+ class tmp(BuildContext):+ cmd = name+ fun = name+ return fun++@bld_command+def foo(ctx):+ print ctx.env+new file mode 100755@@ -0,0 +1,119 @@+#! /bin/sh++# waf configure wrapper++# Fancy colors used to beautify the output a bit.+#+if [ "$NOCOLOR" ] ; then+ NORMAL=""+ BOLD=""+ RED=""+ YELLOW=""+ GREEN=""+else+ NORMAL='\033[0m'+ BOLD='\033[01;1m'+ RED='\033[01;91m'+ YELLOW='\033[00;33m'+ GREEN='\033[01;92m'+fi++EXIT_SUCCESS=0+EXIT_FAILURE=1+EXIT_ERROR=2+EXIT_BUG=10++CUR_DIR=$PWD++#possible relative path+WORKINGDIR=`dirname $0`+cd $WORKINGDIR+#abs path+WORKINGDIR=`pwd`+cd $CUR_DIR+++# Checks for WAF. Honours $WAF if set. Stores path to 'waf' in $WAF.+# Requires that $PYTHON is set.+#+checkWAF()+{+ printf "Checking for WAF\t\t\t: "+ #installed miniwaf in sourcedir+ if [ -z "$WAF" ] ; then+ if [ -f "${WORKINGDIR}/waf" ] ; then+ WAF="${WORKINGDIR}/waf"+ if [ ! -x "$WAF" ] ; then+ chmod +x $WAF+ fi+ fi+ fi+ if [ -z "$WAF" ] ; then+ if [ -f "${WORKINGDIR}/waf-light" ] ; then+ ${WORKINGDIR}/waf-light --make-waf+ WAF="${WORKINGDIR}/waf"+ fi+ fi+ #global installed waf with waf->waf.py link+ if [ -z "$WAF" ] ; then+ WAF=`which waf 2>/dev/null`+ fi+ # neither waf nor miniwaf could be found+ if [ ! -x "$WAF" ] ; then+ printf "$RED""not found""$NORMAL""\n"+ echo "Go to http://code.google.com/p/waf/"+ echo "and download a waf version"+ exit $EXIT_FAILURE+ else+ printf "$GREEN""$WAF""$NORMAL""\n"+ fi+}++# Generates a Makefile. Requires that $WAF is set.+#+generateMakefile()+{+ cat > Makefile << EOF+#!/usr/bin/make -f+# Waf Makefile wrapper+WAF_HOME=$CUR_DIR++all:+#@$WAF build++all-debug:+ @$WAF -v build++all-progress:+ @$WAF -p build++install:+ $WAF install --yes;++uninstall:+ $WAF uninstall++clean:+ @$WAF clean++distclean:+ @$WAF distclean+ @-rm -rf build+ @-rm -f Makefile++check:+ @$WAF check++dist:+ @$WAF dist++.PHONY: clean dist distclean check uninstall install all++EOF+}++checkWAF+generateMakefile++"${WAF}" configure $*+exit $?new file mode 100755@@ -0,0 +1,344 @@+#!/usr/bin/python+# encoding: utf-8++import sys+import os.path+from random import Random+random = Random(0) # initialise with seed to have reproductible benches++# for example: ./genbench.py /tmp/build 50 100 15 5++HELP_USAGE = """Usage: generate_libs.py root libs classes internal external.+ root - Root directory where to create libs.+ libs - Number of libraries (libraries only depend on those with smaller numbers)+ classes - Number of classes per library+ internal - Number of includes per file referring to that same library+ external - Number of includes per file pointing to other libraries++To try the waf part, do:+waf configure build -p -j5++To test the autotools part, do:+touch README AUTHORS NEWS ChangeLog &&+autoreconf --install --symlink --verbose &&+mkdir autotools-build-dir &&+cd autotools-build-dir &&+../configure --disable-shared CXXFLAGS=-Wall &&+time make -j4 --silent &&+time make -j4 --silent+"""++def lib_name(i):+ return "lib_" + str(i)++def createHeader(name):+ filename = name + ".h"+ handle = open(filename, "w" )++ guard = name + '_h_'+ handle.write ('#ifndef ' + guard + '\n');+ handle.write ('#define ' + guard + '\n\n');++ handle.write ('class ' + name + ' {\n');+ handle.write ('public:\n');+ handle.write (' ' + name + '();\n');+ handle.write (' ~' + name + '();\n');+ handle.write ('};\n\n');++ handle.write ('#endif\n');+++def createCPP(name, lib_number, classes_per_lib, internal_includes, external_includes):+ filename = name + ".cpp"+ handle = open(filename, "w" )++ header= name + ".h"+ handle.write ('#include "' + header + '"\n');++ includes = random.sample(range(classes_per_lib), internal_includes)+ for i in includes:+ handle.write ('#include "class_' + str(i) + '.h"\n')++ if (lib_number > 0):+ includes = random.sample(range(classes_per_lib), external_includes)+ lib_list = range(lib_number)+ for i in includes:+ libname = 'lib_' + str(random.choice(lib_list))+ handle.write ('#include <' + libname + '/' + 'class_' + str(i) + '.h>\n')++ handle.write ('\n');+ handle.write (name + '::' + name + '() {}\n');+ handle.write (name + '::~' + name + '() {}\n');+++def createSConscript(lib_number, classes):+ handle = open("SConscript", "w");+ handle.write("Import('env')\n")+ handle.write('list = Split("""\n');+ for i in range(classes):+ handle.write(' class_' + str(i) + '.cpp\n')+ handle.write(' """)\n\n')+ handle.write('env.StaticLibrary("lib_' + str(lib_number) + '", list)\n\n')++def createLibCMakeLists(lib_number, classes):+ handle = open("CMakeLists.txt", "w")+ handle.write("""add_library(lib_%s STATIC %s)\n""" % (str(lib_number), ' '.join(('class_%s' % str(i) for i in range(classes)))))++def createLibMakefile(lib_number, classes):+ handle = open("Makefile", "w");+ handle.write ("""COMPILER = g+++INC = -I..+CCFLAGS = -g -Wall $(INC)+ARCHIVE = ar+DEPEND = makedepend+.SUFFIXES: .o .cpp++""")+ handle.write ("lib = lib_" + str(lib_number) + ".a\n")+ handle.write ("src = \\\n")+ for i in range(classes):+ handle.write('class_' + str(i) + '.cpp \\\n')+ handle.write ("""++objects = $(patsubst %.cpp, %.o, $(src))++all: depend $(lib)++$(lib): $(objects)+ $(ARCHIVE) cr $@ $^+ touch $@++.cpp.o:+ $(COMPILER) $(CCFLAGS) -c $<++clean:+ @rm $(objects) $(lib) 2> /dev/null++depend:+ @$(DEPEND) $(INC) $(src)++""")++def createLibJamFile(lib_number, classes):+ handle = open("Jamfile", "w")+ handle.write ("SubDir TOP lib_" + str(lib_number) + " ;\n\n")+ handle.write ("SubDirHdrs $(INCLUDES) ;\n\n")+ handle.write ("Library lib_" + str(lib_number) + " :\n")+ for i in range(classes):+ handle.write(' class_' + str(i) + '.cpp\n')+ handle.write (' ;\n')++def createVCProjFile(lib_number, classes):+ handle = open("lib_" + str(lib_number) + ".vcproj", "w")+ handle.write("""<?xml version="1.0" encoding="Windows-1252"?>+<VisualStudioProject+ ProjectType="Visual C++"+ Version="7.10"+ Name=""" + '"' + lib_name(lib_number) + '"' + """+ ProjectGUID="{CF495178-8865-4D20-939D-AAA""" + str(lib_number) + """}"+ Keyword="Win32Proj">+ <Platforms>+ <Platform+ Name="Win32"/>+ </Platforms>+ <Configurations>+ <Configuration+ Name="Debug|Win32"+ OutputDirectory="Debug"+ IntermediateDirectory="Debug"+ ConfigurationType="4"+ CharacterSet="2">+ <Tool+ Name="VCCLCompilerTool"+ Optimization="0"+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"+ AdditionalIncludeDirectories=".."+ MinimalRebuild="TRUE"+ BasicRuntimeChecks="3"+ RuntimeLibrary="5"+ UsePrecompiledHeader="0"+ WarningLevel="3"+ Detect64BitPortabilityProblems="TRUE"+ DebugInformationFormat="4"/>+ <Tool+ Name="VCCustomBuildTool"/>+ <Tool+ Name="VCLibrarianTool"+ OutputFile="$(OutDir)/""" + lib_name(lib_number) + """.lib"/>+ </Configuration>+ </Configurations>+ <References>+ </References>+ <Files>+""")++ for i in range(classes):+ handle.write(' <File RelativePath=".\class_' + str(i) + '.cpp"/>\n')++ handle.write("""+ </Files>+ <Globals>+ </Globals>+</VisualStudioProject>+""")++def createLibrary(lib_number, classes, internal_includes, external_includes):+ name = "lib_" + str(lib_number)+ setDir(name)+ for i in range(classes):+ classname = "class_" + str(i)+ createHeader(classname)+ createCPP(classname, lib_number, classes, internal_includes, external_includes)+ createSConscript(lib_number, classes)+ createLibCMakeLists(lib_number, classes)+ createLibMakefile(lib_number, classes)+ createAutotools(lib_number, classes)++ os.chdir("..")++def createCMakeLists(libs):+ handle = open("CMakeLists.txt", "w")+ handle.write("""project('profiling-test')+cmake_minimum_required(VERSION 2.8)++include_directories(${CMAKE_SOURCE_DIR})+""")++ for i in range(libs):+ handle.write("""add_subdirectory(lib_%s)\n""" % str(i))++def createSConstruct(libs):+ handle = open("SConstruct", "w");+ handle.write("""env = Environment(CPPFLAGS=['-Wall'], CPPDEFINES=['LINUX'], CPPPATH=[Dir('#')])\n""")+ handle.write("""env.Decider('timestamp-newer')\n""")+ handle.write("""env.SetOption('implicit_cache', True)\n""")+ handle.write("""env.SourceCode('.', None)\n""")++ for i in range(libs):+ handle.write("""env.SConscript("lib_%s/SConscript", exports=['env'])\n""" % str(i))++def createFullMakefile(libs):+ handle = open("Makefile", "w")++ handle.write('subdirs = \\\n')+ for i in range(libs):+ handle.write('lib_' + str(i) + '\\\n')+ handle.write("""++all: $(subdirs)+ @for i in $(subdirs); do \+ $(MAKE) -C $$i all; done++clean:+ @for i in $(subdirs); do \+ (cd $$i; $(MAKE) clean); done++depend:+ @for i in $(subdirs); do \+ (cd $$i; $(MAKE) depend); done+""")++def createFullJamfile(libs):+ handle = open("Jamfile", "w")+ handle.write ("SubDir TOP ;\n\n")++ for i in range(libs):+ handle.write('SubInclude TOP ' + lib_name(i) + ' ;\n')++ handle = open("Jamrules", "w")+ handle.write('INCLUDES = $(TOP) ;\n')++WT = """#! /usr/bin/env python+# encoding: utf-8++VERSION = '0.0.2'+APPNAME = 'build_bench'+top = '.'+out = 'out'++def configure(conf):+ conf.load('g++')++def build(bld):+ for i in range(%d):+ filez = ' '.join(['lib_%%d/class_%%d.cpp' %% (i, j) for j in range(%d)])+ bld.stlib(+ source = filez,+ target = 'lib_%%d' %% i,+ includes = '.', # include the top-level+ )+"""++def createWtop(libs, classes):+ f = open('wscript', 'w')+ f.write(WT % (libs, classes))+ f.close()++def createFullSolution(libs):+ handle = open("solution.sln", "w")+ handle.write("Microsoft Visual Studio Solution File, Format Version 8.00\n")++ for i in range(libs):+ project_name = lib_name(i) + '\\' + lib_name(i) + '.vcproj'+ handle.write('Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "' + lib_name(i) ++ '", "' + project_name + '", "{CF495178-8865-4D20-939D-AAA' + str(i) + '}"\n')+ handle.write('EndProject\n')++def createAutotoolsTop(libs):+ handle = open("configure.ac", "w")+ handle.write('''\+AC_INIT([bench], [1.0.0])+AC_CONFIG_AUX_DIR([autotools-aux])+AM_INIT_AUTOMAKE([subdir-objects nostdinc no-define tar-pax dist-bzip2])+AM_PROG_LIBTOOL+AC_CONFIG_HEADERS([config.h])+AC_CONFIG_FILES([Makefile])+AC_OUTPUT+''')++ handle = open("Makefile.am", "w")+ handle.write('''\+AM_CPPFLAGS = -I$(srcdir)+lib_LTLIBRARIES =+''')+ for i in range(libs): handle.write('include lib_%s/Makefile.am\n' % str(i))++def createAutotools(lib_number, classes):++ handle = open("Makefile.am", "w")+ handle.write('''\+lib_LTLIBRARIES += lib%s.la+lib%s_la_SOURCES =''' % (str(lib_number), str(lib_number)))+ for i in range(classes): handle.write(' lib_%s/class_%s.cpp' % (str(lib_number), str(i)))+ handle.write('\n')++def setDir(dir):+ if (not os.path.exists(dir)):+ os.mkdir(dir)+ os.chdir(dir)++def main(argv):+ if len(argv) != 6:+ print(HELP_USAGE)+ return++ root_dir = argv[1]+ libs = int(argv[2])+ classes = int(argv[3])+ internal_includes = int(argv[4])+ external_includes = int(argv[5])++ setDir(root_dir)+ for i in range(libs):+ createLibrary(i, classes, internal_includes, external_includes)++ createSConstruct(libs)+ createCMakeLists(libs)+ createFullMakefile(libs)+ createWtop(libs, classes)+ createAutotoolsTop(libs)++if __name__ == "__main__":+ main( sys.argv )++new file mode 100644@@ -0,0 +1,25 @@+Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++3. The name of the author may not be used to endorse or promote products+ derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.new file mode 100644@@ -0,0 +1,42 @@+#Waf-launcher+This is a simple wrapper for the +[waf build system](http://code.google.com/p/waf/)++Since many windows users does not have python installed by default, +the exe file from this project can be included along with the copy of +waf to wrap waf to install python on demand.++The requirements is only .Net 2.0 whics is either Windows Server 2003 R2 +and up, or Windows Vista and up. There is a good chance it is installed +in many OEM installs of Windows XP as well++##How to compile+use either waf or monodevelop (wscript and project files is in the repository)++##How to use++Assume we have a repository, myrepo, where wscript and waf already exists.++ myrepo/waf+ myrepo/wscript++now copy waf-launcher/bin/Release/waf.exe to the repository++ myrepo/waf.exe++Linux users can continue to use `./waf`, just like+Windows users can continue to use `python waf`++For Windows users there is now a second way to invoke waf by writing +either `waf.exe` or simply just `waf`.++When the Windows users does that the following happens:++1. It tries "python waf"+2. If 1 failed it tries "C:\python27\python.exe waf"+3. If 2 failed it ask for permission to install python+4. If pemission is given it tries to install python silently+5. step 1 and 2 it done again+6. If this still fails we exit with an error++Any arguments to `waf.exe` is passed on to `waf`new file mode 100644@@ -0,0 +1,21 @@+ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "waf-launcher", "waf-launcher\waf-launcher.csproj", "{63E79792-BE8F-4AE5-9A99-99B1AE4D96E3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {63E79792-BE8F-4AE5-9A99-99B1AE4D96E3}.Debug|x86.ActiveCfg = Debug|x86 + {63E79792-BE8F-4AE5-9A99-99B1AE4D96E3}.Debug|x86.Build.0 = Debug|x86 + {63E79792-BE8F-4AE5-9A99-99B1AE4D96E3}.Release|x86.ActiveCfg = Release|x86 + {63E79792-BE8F-4AE5-9A99-99B1AE4D96E3}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = waf-launcher\waf-launcher.csproj + version = 1.0 + EndGlobalSection +EndGlobal new file mode 100644@@ -0,0 +1,27 @@+using System.Reflection;+using System.Runtime.CompilerServices;++// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project.++[assembly: AssemblyTitle("waf-launcher")]+[assembly: AssemblyDescription("")]+[assembly: AssemblyConfiguration("")]+[assembly: AssemblyCompany("")]+[assembly: AssemblyProduct("")]+[assembly: AssemblyCopyright("")]+[assembly: AssemblyTrademark("")]+[assembly: AssemblyCulture("")]++// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".+// The form "{Major}.{Minor}.*" will automatically update the build and revision,+// and "{Major}.{Minor}.{Build}.*" will update just the revision.++[assembly: AssemblyVersion("1.0.*")]++// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing.++//[assembly: AssemblyDelaySign(false)]+//[assembly: AssemblyKeyFile("")]+new file mode 100644@@ -0,0 +1,99 @@+using System;+using System.Diagnostics;++namespace waflauncher+{+ class MainClass+ {+ public static System.Diagnostics.Process exec(string command,params string[] args) {+ String argstring = String.Join(" ",args);+ System.Diagnostics.ProcessStartInfo startinfo = new System.Diagnostics.ProcessStartInfo(command,argstring);+ startinfo.UseShellExecute = false;+ System.Diagnostics.Process p;+ try {+ p = Process.Start(startinfo);+ } catch (System.ComponentModel.Win32Exception){+ return null;+ }+ p.WaitForExit();+ return p;+ }++ public static int Main (string[] args)+ {+ //I run waf and if not succesful we try on-the-fly install of python+ if(!runWaf(args)){+ //but first we ask the user if it's okay to install software on their computer+ if(mayInstall()){+ //I install python and try running waf yet another time+ installPython();+ if(!runWaf(args)){+ //If it still fails something has gone horrible wrong+ Console.WriteLine("Python not fully working");+ return 1;+ }+ } else {+ Console.WriteLine("Not automatically installing Python");+ Console.WriteLine("Please download and install http://www.python.org/ftp/python/2.7.1/python-2.7.1.msi");+ Console.WriteLine("or if you have python installed make sure it is on %PATH%");+ Console.WriteLine("or run this command again and answer yes");+ }+ }+ return 0;+ }++ public static bool mayInstall() {+ Console.Write("Download and install python [Y/n]? ");+ ConsoleKeyInfo a = Console.ReadKey();+ Console.WriteLine();+ switch(a.KeyChar){+ case 'Y':+ case 'y':+ case '\n':+ case '\r':+ return true;+ //If unsure default to not doing it+ default:+ return false;+ }+ }++ public static String getwafDir(){+ //This changes the current directory to the place where the exe exists+ System.Reflection.Assembly a = System.Reflection.Assembly.GetEntryAssembly();+ String path = System.IO.Path.GetDirectoryName(a.Location);+ return path + System.IO.Path.DirectorySeparatorChar;+ }++ public static bool runWaf(string[] args){+ Process p = exec("python", getwafDir() + "waf", String.Join(" ",args));+ //If command could be execeuted return true+ if (p != null) return true;+ //If not try with the direct path to the default installation which is where installPython() will install it to+ //This is done since the %PATH% variable might not be setup to include python++ List<String> versions = new List<String>() { "27", "32", "26", "31", "25", "30" };+ foreach (String v in versions) {+ p = exec("C:\\Python"+v+"\\python.exe", "waf", String.Join(" ",args));+ if (p != null) return true;+ }+ return false;+ }++ public static void installPython(){+ //Make a filename to download python to+ String filename = System.IO.Path.GetTempPath() + Char.ToString(System.IO.Path.DirectorySeparatorChar) + "python-2.7.1.msi";++ System.Net.WebClient web = new System.Net.WebClient();+ Console.WriteLine ("Downloading python 2.7");+ web.DownloadFile("http://www.python.org/ftp/python/2.7.1/python-2.7.1.msi",filename);+ Console.WriteLine ("python2.7 downloaded to " + filename);++ Console.WriteLine ("Installing python");+ //filename must be qouted or else msiexec will fail+ exec("msiexec","/qn","/i","\"" +filename + "\"");+ Console.WriteLine ("Python is now installed");+ }+ }+}+new file mode 100644@@ -0,0 +1,50 @@+<?xml version="1.0" encoding="utf-8"?>+<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">+ <PropertyGroup>+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>+ <ProductVersion>9.0.21022</ProductVersion>+ <SchemaVersion>2.0</SchemaVersion>+ <ProjectGuid>{63E79792-BE8F-4AE5-9A99-99B1AE4D96E3}</ProjectGuid>+ <OutputType>Exe</OutputType>+ <RootNamespace>waflauncher</RootNamespace>+ <AssemblyName>waf</AssemblyName>+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>+ <ReleaseVersion>1.0</ReleaseVersion>+ </PropertyGroup>+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">+ <DebugSymbols>true</DebugSymbols>+ <DebugType>full</DebugType>+ <Optimize>false</Optimize>+ <OutputPath>bin\Debug</OutputPath>+ <DefineConstants>DEBUG</DefineConstants>+ <ErrorReport>prompt</ErrorReport>+ <WarningLevel>4</WarningLevel>+ <PlatformTarget>x86</PlatformTarget>+ <Externalconsole>true</Externalconsole>+ </PropertyGroup>+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">+ <DebugType>none</DebugType>+ <Optimize>false</Optimize>+ <OutputPath>bin\Release</OutputPath>+ <ErrorReport>prompt</ErrorReport>+ <WarningLevel>4</WarningLevel>+ <PlatformTarget>x86</PlatformTarget>+ <Externalconsole>true</Externalconsole>+ </PropertyGroup>+ <ItemGroup>+ <Reference Include="System" />+ </ItemGroup>+ <ItemGroup>+ <Compile Include="Main.cs" />+ <Compile Include="AssemblyInfo.cs" />+ </ItemGroup>+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />+ <ProjectExtensions>+ <MonoDevelop>+ <Properties>+ <Deployment.LinuxDeployData generateScript="false" />+ </Properties>+ </MonoDevelop>+ </ProjectExtensions>+</Project>\ No newline at end of filenew file mode 100644@@ -0,0 +1,7 @@+out = 'waf-launcher/bin/Release'++def configure(config):+ config.load('cs')++def build(bld):+ bld(features='cs',source='waf-launcher/Main.cs', type='exe',gen='waf.exe')new file mode 100644@@ -0,0 +1,100 @@+@echo off + +rem from issue #964 + +Setlocal EnableDelayedExpansion + +rem Check Windows Version +set TOKEN=tokens=3* +ver | findstr /i "5\.0\." > nul +if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=3* +ver | findstr /i "5\.1\." > nul +if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=3* +ver | findstr /i "5\.2\." > nul +if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=3* +ver | findstr /i "6\.0\." > nul +if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=2* +ver | findstr /i "6\.1\." > nul +if %ERRORLEVEL% EQU 0 SET TOKEN=tokens=2* + +rem Start calculating PYTHON and PYTHON_DIR +set PYTHON= +set PYTHON_DIR= + +Setlocal EnableDelayedExpansion + +set PYTHON_DIR_OK=FALSE +set REGPATH= + +for %%i in (3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0 2.7 2.6 2.5 2.4 2.3) do ( +for %%j in (HKCU HKLM) do ( +for %%k in (SOFTWARE\Wow6432Node SOFTWARE) do ( +for %%l in (Python\PythonCore IronPython) do ( +set REG_PYTHON_EXE=python.exe +if "%%l"=="IronPython" ( +set REG_PYTHON_EXE=ipy.exe +) + +@echo on + +set REGPATH=%%j\%%k\%%l\%%i\InstallPath +rem @echo Regpath !REGPATH! +REG QUERY "!REGPATH!" /ve 1>nul 2>nul +if !ERRORLEVEL! equ 0 ( + for /F "%TOKEN% delims= " %%A IN ('REG QUERY "!REGPATH!" /ve') do @set REG_PYTHON_DIR=%%B + if exist !REG_PYTHON_DIR! ( + set REG_PYTHON=!REG_PYTHON_DIR!!REG_PYTHON_EXE! + rem set PYTHON_DIR_OK=TRUE + if "!PYTHON_DIR_OK!"=="FALSE" ( + set PYTHON_DIR=!REG_PYTHON_DIR! + set PYTHON=!REG_PYTHON! + set PYTHON_DIR_OK=TRUE + ) + + rem set PYTHON_DIR_OK=FALSE + rem @echo Find !REG_PYTHON! + rem goto finished + ) +) + +echo off + +) +rem for l +) +rem for k +) +rem for j +) +rem for i + + + +:finished + +Endlocal & SET PYTHON_DIR=%PYTHON_DIR% & SET PYTHON=%PYTHON% + +if "%PYTHON_DIR%" == "" ( +rem @echo No Python dir +set PYTHON=python +goto running +) + +rem @echo %PYTHON_DIR% + +if "%PYTHON%" == "" ( +rem @echo No Python +set PYTHON=python +goto running +) + +set PYTHON_INCLUDE=%PYTHON_DIR%include +set PYTHON_LIB=%PYTHON_DIR%libs\python27.lib +set PATH=%PYTHON_DIR%;%PYTHON_DIR%Scripts;%PYTHON_DIR%Tools\Scripts;%PATH% + +:running + +@echo Using %PYTHON% + +"%PYTHON%" -x "%~dp0waf" %* & Endlocal & exit /b + new file mode 100755@@ -0,0 +1,166 @@+#!/usr/bin/env python+# encoding: ISO8859-1+# Thomas Nagy, 2005-2012++"""+Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++3. The name of the author may not be used to endorse or promote products+ derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.+"""++import os, sys++VERSION="1.7.6"+REVISION="x"+INSTALL="x"+C1='x'+C2='x'+cwd = os.getcwd()+join = os.path.join++if sys.hexversion<0x206000f:+ raise ImportError('Python >= 2.6 is required to create the waf file')++WAF='waf'+def b(x):+ return x+if sys.hexversion>0x300000f:+ WAF='waf3'+ def b(x):+ return x.encode()++def err(m):+ print(('\033[91mError: %s\033[0m' % m))+ sys.exit(1)++def unpack_wafdir(dir):+ f = open(sys.argv[0],'rb')+ c = 'corrupt archive (%d)'+ while 1:+ line = f.readline()+ if not line: err('run waf-light from a folder containing waflib')+ if line == b('#==>\n'):+ txt = f.readline()+ if not txt: err(c % 1)+ if f.readline() != b('#<==\n'): err(c % 2)+ break+ if not txt: err(c % 3)+ txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r'))++ import shutil, tarfile+ try: shutil.rmtree(dir)+ except OSError: pass+ try:+ for x in ['Tools', 'extras']:+ os.makedirs(join(dir, 'waflib', x))+ except OSError:+ err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir)++ os.chdir(dir)+ tmp = 't.bz2'+ t = open(tmp,'wb')+ try: t.write(txt)+ finally: t.close()++ try:+ t = tarfile.open(tmp)+ except:+ try:+ os.system('bunzip2 t.bz2')+ t = tarfile.open('t')+ tmp = 't'+ except:+ os.chdir(cwd)+ try: shutil.rmtree(dir)+ except OSError: pass+ err("Waf cannot be unpacked, check that bzip2 support is present")++ try:+ for x in t: t.extract(x)+ finally:+ t.close()++ for x in ['Tools', 'extras']:+ os.chmod(join('waflib',x), 493)++ if sys.hexversion<0x300000f:+ sys.path = [join(dir, 'waflib')] + sys.path+ import fixpy2+ fixpy2.fixdir(dir)++ os.unlink(tmp)+ os.chdir(cwd)++ try: dir = unicode(dir, 'mbcs')+ except: pass+ try:+ from ctypes import windll+ windll.kernel32.SetFileAttributesW(dir, 2)+ except:+ pass++def test(dir):+ try:+ os.stat(join(dir, 'waflib'))+ return os.path.abspath(dir)+ except OSError:+ pass++def find_lib():+ name = sys.argv[0]+ base = os.path.dirname(os.path.abspath(name))++ #devs use $WAFDIR+ w=test(os.environ.get('WAFDIR', ''))+ if w: return w++ #waf-light+ if name.endswith('waf-light'):+ w = test(base)+ if w: return w+ err('waf-light requires waflib -> export WAFDIR=/folder')++ dirname = '%s-%s-%s' % (WAF, VERSION, REVISION)+ for i in [INSTALL,'/usr','/usr/local','/opt']:+ w = test(i + '/lib/' + dirname)+ if w: return w++ #waf-local+ dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname)+ w = test(dir)+ if w: return w++ #unpack+ unpack_wafdir(dir)+ return dir++wafdir = find_lib()+sys.path.insert(0, wafdir)++if __name__ == '__main__':+ #import waflib.extras.compat15#PRELUDE+ from waflib import Scripting+ Scripting.waf_entry_point(cwd, VERSION, wafdir)+new file mode 100644@@ -0,0 +1,1358 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""+Classes related to the build phase (build, clean, install, step, etc)++The inheritance tree is the following:++"""++import os, sys, errno, re, shutil+try:+ import cPickle+except ImportError:+ import pickle as cPickle+from waflib import Runner, TaskGen, Utils, ConfigSet, Task, Logs, Options, Context, Errors+import waflib.Node++CACHE_DIR = 'c4che'+"""Location of the cache files"""++CACHE_SUFFIX = '_cache.py'+"""Suffix for the cache files"""++INSTALL = 1337+"""Positive value '->' install, see :py:attr:`waflib.Build.BuildContext.is_install`"""++UNINSTALL = -1337+"""Negative value '<-' uninstall, see :py:attr:`waflib.Build.BuildContext.is_install`"""++SAVED_ATTRS = 'root node_deps raw_deps task_sigs'.split()+"""Build class members to save between the runs (root, node_deps, raw_deps, task_sigs)"""++CFG_FILES = 'cfg_files'+"""Files from the build directory to hash before starting the build (``config.h`` written during the configuration)"""++POST_AT_ONCE = 0+"""Post mode: all task generators are posted before the build really starts"""++POST_LAZY = 1+"""Post mode: post the task generators group after group"""++POST_BOTH = 2+"""Post mode: post the task generators at once, then re-check them for each group"""++class BuildContext(Context.Context):+ '''executes the build'''++ cmd = 'build'+ variant = ''++ def __init__(self, **kw):+ super(BuildContext, self).__init__(**kw)++ self.is_install = 0+ """Non-zero value when installing or uninstalling file"""++ self.top_dir = kw.get('top_dir', Context.top_dir)++ self.run_dir = kw.get('run_dir', Context.run_dir)++ self.post_mode = POST_AT_ONCE+ """post the task generators at once, group-by-group, or both"""++ # output directory - may be set until the nodes are considered+ self.out_dir = kw.get('out_dir', Context.out_dir)++ self.cache_dir = kw.get('cache_dir', None)+ if not self.cache_dir:+ self.cache_dir = self.out_dir + os.sep + CACHE_DIR++ # map names to environments, the '' must be defined+ self.all_envs = {}++ # ======================================= #+ # cache variables++ self.task_sigs = {}+ """Signatures of the tasks (persists between build executions)"""++ self.node_deps = {}+ """Dict of node dependencies found by :py:meth:`waflib.Task.Task.scan` (persists between build executions)"""++ self.raw_deps = {}+ """Dict of custom data returned by :py:meth:`waflib.Task.Task.scan` (persists between build executions)"""++ # list of folders that are already scanned+ # so that we do not need to stat them one more time+ self.cache_dir_contents = {}++ self.task_gen_cache_names = {}++ self.launch_dir = Context.launch_dir++ self.jobs = Options.options.jobs+ self.targets = Options.options.targets+ self.keep = Options.options.keep+ self.cache_global = Options.cache_global+ self.nocache = Options.options.nocache+ self.progress_bar = Options.options.progress_bar++ ############ stuff below has not been reviewed++ # Manual dependencies.+ self.deps_man = Utils.defaultdict(list)+ """Manual dependencies set by :py:meth:`waflib.Build.BuildContext.add_manual_dependency`"""++ # just the structure here+ self.current_group = 0+ """+ Current build group+ """++ self.groups = []+ """+ List containing lists of task generators+ """+ self.group_names = {}+ """+ Map group names to the group lists. See :py:meth:`waflib.Build.BuildContext.add_group`+ """++ def get_variant_dir(self):+ """Getter for the variant_dir attribute"""+ if not self.variant:+ return self.out_dir+ return os.path.join(self.out_dir, self.variant)+ variant_dir = property(get_variant_dir, None)++ def __call__(self, *k, **kw):+ """+ Create a task generator and add it to the current build group. The following forms are equivalent::++ def build(bld):+ tg = bld(a=1, b=2)++ def build(bld):+ tg = bld()+ tg.a = 1+ tg.b = 2++ def build(bld):+ tg = TaskGen.task_gen(a=1, b=2)+ bld.add_to_group(tg, None)++ :param group: group name to add the task generator to+ :type group: string+ """+ kw['bld'] = self+ ret = TaskGen.task_gen(*k, **kw)+ self.task_gen_cache_names = {} # reset the cache, each time+ self.add_to_group(ret, group=kw.get('group', None))+ return ret+ + def rule(self, *k, **kw):+ """+ Wrapper for creating a task generator using the decorator notation.+++ The the following code:++ @bld.rule(+ target = "foo"+ )+ def _(tsk):+ print("bar")++ is equivalent to:++ def bar(tsk):+ print("bar")++ bld(+ target = "foo",+ rule = bar,+ )+ """+ def f(rule):+ ret = self(*k, **kw)+ ret.rule = rule+ return ret+ return f++ def __copy__(self):+ """Implemented to prevents copies of build contexts (raises an exception)"""+ raise Errors.WafError('build contexts are not supposed to be copied')++ def install_files(self, *k, **kw):+ """Actual implementation provided by :py:meth:`waflib.Build.InstallContext.install_files`"""+ pass++ def install_as(self, *k, **kw):+ """Actual implementation provided by :py:meth:`waflib.Build.InstallContext.install_as`"""+ pass++ def symlink_as(self, *k, **kw):+ """Actual implementation provided by :py:meth:`waflib.Build.InstallContext.symlink_as`"""+ pass++ def load_envs(self):+ """+ The configuration command creates files of the form ``build/c4che/NAMEcache.py``. This method+ creates a :py:class:`waflib.ConfigSet.ConfigSet` instance for each ``NAME`` by reading those+ files. The config sets are then stored in the dict :py:attr:`waflib.Build.BuildContext.allenvs`.+ """+ node = self.root.find_node(self.cache_dir)+ if not node:+ raise Errors.WafError('The project was not configured: run "waf configure" first!')+ lst = node.ant_glob('**/*%s' % CACHE_SUFFIX, quiet=True)++ if not lst:+ raise Errors.WafError('The cache directory is empty: reconfigure the project')++ for x in lst:+ name = x.path_from(node).replace(CACHE_SUFFIX, '').replace('\\', '/')+ env = ConfigSet.ConfigSet(x.abspath())+ self.all_envs[name] = env+ for f in env[CFG_FILES]:+ newnode = self.root.find_resource(f)+ try:+ h = Utils.h_file(newnode.abspath())+ except (IOError, AttributeError):+ Logs.error('cannot find %r' % f)+ h = Utils.SIG_NIL+ newnode.sig = h++ def init_dirs(self):+ """+ Initialize the project directory and the build directory by creating the nodes+ :py:attr:`waflib.Build.BuildContext.srcnode` and :py:attr:`waflib.Build.BuildContext.bldnode`+ corresponding to ``top_dir`` and ``variant_dir`` respectively. The ``bldnode`` directory will be+ created if it does not exist.+ """++ if not (os.path.isabs(self.top_dir) and os.path.isabs(self.out_dir)):+ raise Errors.WafError('The project was not configured: run "waf configure" first!')++ self.path = self.srcnode = self.root.find_dir(self.top_dir)+ self.bldnode = self.root.make_node(self.variant_dir)+ self.bldnode.mkdir()++ def execute(self):+ """+ Restore the data from previous builds and call :py:meth:`waflib.Build.BuildContext.execute_build`. Overrides from :py:func:`waflib.Context.Context.execute`+ """+ self.restore()+ if not self.all_envs:+ self.load_envs()++ self.execute_build()++ def execute_build(self):+ """+ Execute the build by:++ * reading the scripts (see :py:meth:`waflib.Context.Context.recurse`)+ * calling :py:meth:`waflib.Build.BuildContext.pre_build` to call user build functions+ * calling :py:meth:`waflib.Build.BuildContext.compile` to process the tasks+ * calling :py:meth:`waflib.Build.BuildContext.post_build` to call user build functions+ """++ Logs.info("Waf: Entering directory `%s'" % self.variant_dir)+ self.recurse([self.run_dir])+ self.pre_build()++ # display the time elapsed in the progress bar+ self.timer = Utils.Timer()++ if self.progress_bar:+ sys.stderr.write(Logs.colors.cursor_off)+ try:+ self.compile()+ finally:+ if self.progress_bar == 1:+ c = len(self.returned_tasks) or 1+ self.to_log(self.progress_line(c, c, Logs.colors.BLUE, Logs.colors.NORMAL))+ print('')+ sys.stdout.flush()+ sys.stderr.write(Logs.colors.cursor_on)+ Logs.info("Waf: Leaving directory `%s'" % self.variant_dir)+ self.post_build()++ def restore(self):+ """+ Load the data from a previous run, sets the attributes listed in :py:const:`waflib.Build.SAVED_ATTRS`+ """+ try:+ env = ConfigSet.ConfigSet(os.path.join(self.cache_dir, 'build.config.py'))+ except (IOError, OSError):+ pass+ else:+ if env['version'] < Context.HEXVERSION:+ raise Errors.WafError('Version mismatch! reconfigure the project')+ for t in env['tools']:+ self.setup(**t)++ f = None+ try:+ dbfn = os.path.join(self.variant_dir, Context.DBFILE)+ try:+ f = open(dbfn, 'rb')+ except (IOError, EOFError):+ # handle missing file/empty file+ Logs.debug('build: Could not load the build cache %s (missing)' % dbfn)+ else:+ try:+ waflib.Node.pickle_lock.acquire()+ waflib.Node.Nod3 = self.node_class+ try:+ data = cPickle.load(f)+ except Exception as e:+ Logs.debug('build: Could not pickle the build cache %s: %r' % (dbfn, e))+ else:+ for x in SAVED_ATTRS:+ setattr(self, x, data[x])+ finally:+ waflib.Node.pickle_lock.release()+ finally:+ if f:+ f.close()++ self.init_dirs()++ def store(self):+ """+ Store the data for next runs, sets the attributes listed in :py:const:`waflib.Build.SAVED_ATTRS`. Uses a temporary+ file to avoid problems on ctrl+c.+ """++ data = {}+ for x in SAVED_ATTRS:+ data[x] = getattr(self, x)+ db = os.path.join(self.variant_dir, Context.DBFILE)++ try:+ waflib.Node.pickle_lock.acquire()+ waflib.Node.Nod3 = self.node_class++ f = None+ try:+ f = open(db + '.tmp', 'wb')+ cPickle.dump(data, f, -1)+ finally:+ if f:+ f.close()+ finally:+ waflib.Node.pickle_lock.release()++ try:+ st = os.stat(db)+ os.unlink(db)+ if not Utils.is_win32: # win32 has no chown but we're paranoid+ os.chown(db + '.tmp', st.st_uid, st.st_gid)+ except (AttributeError, OSError):+ pass++ # do not use shutil.move (copy is not thread-safe)+ os.rename(db + '.tmp', db)++ def compile(self):+ """+ Run the build by creating an instance of :py:class:`waflib.Runner.Parallel`+ The cache file is not written if the build is up to date (no task executed).+ """+ Logs.debug('build: compile()')++ # use another object to perform the producer-consumer logic (reduce the complexity)+ self.producer = Runner.Parallel(self, self.jobs)+ self.producer.biter = self.get_build_iterator()+ self.returned_tasks = [] # not part of the API yet+ try:+ self.producer.start()+ except KeyboardInterrupt:+ self.store()+ raise+ else:+ if self.producer.dirty:+ self.store()++ if self.producer.error:+ raise Errors.BuildError(self.producer.error)++ def setup(self, tool, tooldir=None, funs=None):+ """+ Import waf tools, used to import those accessed during the configuration::++ def configure(conf):+ conf.load('glib2')++ def build(bld):+ pass # glib2 is imported implicitly++ :param tool: tool list+ :type tool: list+ :param tooldir: optional tool directory (sys.path)+ :type tooldir: list of string+ :param funs: unused variable+ """+ if isinstance(tool, list):+ for i in tool: self.setup(i, tooldir)+ return++ module = Context.load_tool(tool, tooldir)+ if hasattr(module, "setup"): module.setup(self)++ def get_env(self):+ """Getter for the env property"""+ try:+ return self.all_envs[self.variant]+ except KeyError:+ return self.all_envs['']+ def set_env(self, val):+ """Setter for the env property"""+ self.all_envs[self.variant] = val++ env = property(get_env, set_env)++ def add_manual_dependency(self, path, value):+ """+ Adds a dependency from a node object to a value::++ def build(bld):+ bld.add_manual_dependency(+ bld.path.find_resource('wscript'),+ bld.root.find_resource('/etc/fstab'))++ :param path: file path+ :type path: string or :py:class:`waflib.Node.Node`+ :param value: value to depend on+ :type value: :py:class:`waflib.Node.Node`, string, or function returning a string+ """+ if path is None:+ raise ValueError('Invalid input')++ if isinstance(path, waflib.Node.Node):+ node = path+ elif os.path.isabs(path):+ node = self.root.find_resource(path)+ else:+ node = self.path.find_resource(path)++ if isinstance(value, list):+ self.deps_man[id(node)].extend(value)+ else:+ self.deps_man[id(node)].append(value)++ def launch_node(self):+ """Returns the launch directory as a :py:class:`waflib.Node.Node` object"""+ try:+ # private cache+ return self.p_ln+ except AttributeError:+ self.p_ln = self.root.find_dir(self.launch_dir)+ return self.p_ln++ def hash_env_vars(self, env, vars_lst):+ """+ Hash configuration set variables::++ def build(bld):+ bld.hash_env_vars(bld.env, ['CXX', 'CC'])++ :param env: Configuration Set+ :type env: :py:class:`waflib.ConfigSet.ConfigSet`+ :param vars_lst: list of variables+ :type vars_list: list of string+ """++ if not env.table:+ env = env.parent+ if not env:+ return Utils.SIG_NIL++ idx = str(id(env)) + str(vars_lst)+ try:+ cache = self.cache_env+ except AttributeError:+ cache = self.cache_env = {}+ else:+ try:+ return self.cache_env[idx]+ except KeyError:+ pass++ lst = [env[a] for a in vars_lst]+ ret = Utils.h_list(lst)+ Logs.debug('envhash: %s %r', Utils.to_hex(ret), lst)++ cache[idx] = ret++ return ret++ def get_tgen_by_name(self, name):+ """+ Retrieves a task generator from its name or its target name+ the name must be unique::++ def build(bld):+ tg = bld(name='foo')+ tg == bld.get_tgen_by_name('foo')+ """+ cache = self.task_gen_cache_names+ if not cache:+ # create the index lazily+ for g in self.groups:+ for tg in g:+ try:+ cache[tg.name] = tg+ except AttributeError:+ # raised if not a task generator, which should be uncommon+ pass+ try:+ return cache[name]+ except KeyError:+ raise Errors.WafError('Could not find a task generator for the name %r' % name)++ def progress_line(self, state, total, col1, col2):+ """+ Compute the progress bar used by ``waf -p``+ """+ n = len(str(total))++ Utils.rot_idx += 1+ ind = Utils.rot_chr[Utils.rot_idx % 4]++ pc = (100.*state)/total+ eta = str(self.timer)+ fs = "[%%%dd/%%%dd][%%s%%2d%%%%%%s][%s][" % (n, n, ind)+ left = fs % (state, total, col1, pc, col2)+ right = '][%s%s%s]' % (col1, eta, col2)++ cols = Logs.get_term_cols() - len(left) - len(right) + 2*len(col1) + 2*len(col2)+ if cols < 7: cols = 7++ ratio = ((cols*state)//total) - 1++ bar = ('='*ratio+'>').ljust(cols)+ msg = Utils.indicator % (left, bar, right)++ return msg++ def declare_chain(self, *k, **kw):+ """+ Wrapper for :py:func:`waflib.TaskGen.declare_chain` provided for convenience+ """+ return TaskGen.declare_chain(*k, **kw)++ def pre_build(self):+ """Execute user-defined methods before the build starts, see :py:meth:`waflib.Build.BuildContext.add_pre_fun`"""+ for m in getattr(self, 'pre_funs', []):+ m(self)++ def post_build(self):+ """Executes the user-defined methods after the build is successful, see :py:meth:`waflib.Build.BuildContext.add_post_fun`"""+ for m in getattr(self, 'post_funs', []):+ m(self)++ def add_pre_fun(self, meth):+ """+ Bind a method to execute after the scripts are read and before the build starts::++ def mycallback(bld):+ print("Hello, world!")++ def build(bld):+ bld.add_pre_fun(mycallback)+ """+ try:+ self.pre_funs.append(meth)+ except AttributeError:+ self.pre_funs = [meth]++ def add_post_fun(self, meth):+ """+ Bind a method to execute immediately after the build is successful::++ def call_ldconfig(bld):+ bld.exec_command('/sbin/ldconfig')++ def build(bld):+ if bld.cmd == 'install':+ bld.add_pre_fun(call_ldconfig)+ """+ try:+ self.post_funs.append(meth)+ except AttributeError:+ self.post_funs = [meth]++ def get_group(self, x):+ """+ Get the group x, or return the current group if x is None++ :param x: name or number or None+ :type x: string, int or None+ """+ if not self.groups:+ self.add_group()+ if x is None:+ return self.groups[self.current_group]+ if x in self.group_names:+ return self.group_names[x]+ return self.groups[x]++ def add_to_group(self, tgen, group=None):+ """add a task or a task generator for the build"""+ # paranoid+ assert(isinstance(tgen, TaskGen.task_gen) or isinstance(tgen, Task.TaskBase))+ tgen.bld = self+ self.get_group(group).append(tgen)++ def get_group_name(self, g):+ """name for the group g (utility)"""+ if not isinstance(g, list):+ g = self.groups[g]+ for x in self.group_names:+ if id(self.group_names[x]) == id(g):+ return x+ return ''++ def get_group_idx(self, tg):+ """+ Index of the group containing the task generator given as argument::++ def build(bld):+ tg = bld(name='nada')+ 0 == bld.get_group_idx(tg)++ :param tg: Task generator object+ :type tg: :py:class:`waflib.TaskGen.task_gen`+ """+ se = id(tg)+ for i in range(len(self.groups)):+ for t in self.groups[i]:+ if id(t) == se:+ return i+ return None++ def add_group(self, name=None, move=True):+ """+ Add a new group of tasks/task generators. By default the new group becomes the default group for new task generators.++ :param name: name for this group+ :type name: string+ :param move: set the group created as default group (True by default)+ :type move: bool+ """+ #if self.groups and not self.groups[0].tasks:+ # error('add_group: an empty group is already present')+ if name and name in self.group_names:+ Logs.error('add_group: name %s already present' % name)+ g = []+ self.group_names[name] = g+ self.groups.append(g)+ if move:+ self.current_group = len(self.groups) - 1++ def set_group(self, idx):+ """+ Set the current group to be idx: now new task generators will be added to this group by default::++ def build(bld):+ bld(rule='touch ${TGT}', target='foo.txt')+ bld.add_group() # now the current group is 1+ bld(rule='touch ${TGT}', target='bar.txt')+ bld.set_group(0) # now the current group is 0+ bld(rule='touch ${TGT}', target='truc.txt') # build truc.txt before bar.txt++ :param idx: group name or group index+ :type idx: string or int+ """+ if isinstance(idx, str):+ g = self.group_names[idx]+ for i in range(len(self.groups)):+ if id(g) == id(self.groups[i]):+ self.current_group = i+ else:+ self.current_group = idx++ def total(self):+ """+ Approximate task count: this value may be inaccurate if task generators are posted lazily (see :py:attr:`waflib.Build.BuildContext.post_mode`).+ The value :py:attr:`waflib.Runner.Parallel.total` is updated during the task execution.+ """+ total = 0+ for group in self.groups:+ for tg in group:+ try:+ total += len(tg.tasks)+ except AttributeError:+ total += 1+ return total++ def get_targets(self):+ """+ Return the task generator corresponding to the 'targets' list, used by :py:meth:`waflib.Build.BuildContext.get_build_iterator`::++ $ waf --targets=myprogram,myshlib+ """+ to_post = []+ min_grp = 0+ for name in self.targets.split(','):+ tg = self.get_tgen_by_name(name)+ if not tg:+ raise Errors.WafError('target %r does not exist' % name)++ m = self.get_group_idx(tg)+ if m > min_grp:+ min_grp = m+ to_post = [tg]+ elif m == min_grp:+ to_post.append(tg)+ return (min_grp, to_post)++ def get_all_task_gen(self):+ """+ Utility method, returns a list of all task generators - if you need something more complicated, implement your own+ """+ lst = []+ for g in self.groups:+ lst.extend(g)+ return lst++ def post_group(self):+ """+ Post the task generators from the group indexed by self.cur, used by :py:meth:`waflib.Build.BuildContext.get_build_iterator`+ """+ if self.targets == '*':+ for tg in self.groups[self.cur]:+ try:+ f = tg.post+ except AttributeError:+ pass+ else:+ f()+ elif self.targets:+ if self.cur < self._min_grp:+ for tg in self.groups[self.cur]:+ try:+ f = tg.post+ except AttributeError:+ pass+ else:+ f()+ else:+ for tg in self._exact_tg:+ tg.post()+ else:+ ln = self.launch_node()+ if ln.is_child_of(self.bldnode):+ Logs.warn('Building from the build directory, forcing --targets=*')+ ln = self.srcnode+ elif not ln.is_child_of(self.srcnode):+ Logs.warn('CWD %s is not under %s, forcing --targets=* (run distclean?)' % (ln.abspath(), self.srcnode.abspath()))+ ln = self.srcnode+ for tg in self.groups[self.cur]:+ try:+ f = tg.post+ except AttributeError:+ pass+ else:+ if tg.path.is_child_of(ln):+ f()++ def get_tasks_group(self, idx):+ """+ Return all the tasks for the group of num idx, used by :py:meth:`waflib.Build.BuildContext.get_build_iterator`+ """+ tasks = []+ for tg in self.groups[idx]:+ try:+ tasks.extend(tg.tasks)+ except AttributeError: # not a task generator, can be the case for installation tasks+ tasks.append(tg)+ return tasks++ def get_build_iterator(self):+ """+ Creates a generator object that returns lists of tasks executable in parallel (yield)++ :return: tasks which can be executed immediatly+ :rtype: list of :py:class:`waflib.Task.TaskBase`+ """+ self.cur = 0++ if self.targets and self.targets != '*':+ (self._min_grp, self._exact_tg) = self.get_targets()++ global lazy_post+ if self.post_mode != POST_LAZY:+ while self.cur < len(self.groups):+ self.post_group()+ self.cur += 1+ self.cur = 0++ while self.cur < len(self.groups):+ # first post the task generators for the group+ if self.post_mode != POST_AT_ONCE:+ self.post_group()++ # then extract the tasks+ tasks = self.get_tasks_group(self.cur)+ # if the constraints are set properly (ext_in/ext_out, before/after)+ # the call to set_file_constraints may be removed (can be a 15% penalty on no-op rebuilds)+ # (but leave set_file_constraints for the installation step)+ #+ # if the tasks have only files, set_file_constraints is required but set_precedence_constraints is not necessary+ #+ Task.set_file_constraints(tasks)+ Task.set_precedence_constraints(tasks)++ self.cur_tasks = tasks+ self.cur += 1+ if not tasks: # return something else the build will stop+ continue+ yield tasks+ while 1:+ yield []+++ #def install_dir(self, path, env=None):+ # """+ # Create empty folders for the installation (very rarely used) TODO+ # """+ # return++class inst(Task.Task):+ """+ Special task used for installing files and symlinks, it behaves both like a task+ and like a task generator+ """+ color = 'CYAN'++ def uid(self):+ lst = [self.dest, self.path] + self.source+ return Utils.h_list(repr(lst))++ def post(self):+ """+ Same interface as in :py:meth:`waflib.TaskGen.task_gen.post`+ """+ buf = []+ for x in self.source:+ if isinstance(x, waflib.Node.Node):+ y = x+ else:+ y = self.path.find_resource(x)+ if not y:+ if Logs.verbose:+ Logs.warn('Could not find %s immediately (may cause broken builds)' % x)+ idx = self.generator.bld.get_group_idx(self)+ for tg in self.generator.bld.groups[idx]:+ if not isinstance(tg, inst) and id(tg) != id(self):+ tg.post()+ y = self.path.find_resource(x)+ if y:+ break+ else:+ raise Errors.WafError('Could not find %r in %r' % (x, self.path))+ buf.append(y)+ self.inputs = buf++ def runnable_status(self):+ """+ Installation tasks are always executed, so this method returns either :py:const:`waflib.Task.ASK_LATER` or :py:const:`waflib.Task.RUN_ME`.+ """+ ret = super(inst, self).runnable_status()+ if ret == Task.SKIP_ME:+ return Task.RUN_ME+ return ret++ def __str__(self):+ """Return an empty string to disable the display"""+ return ''++ def run(self):+ """The attribute 'exec_task' holds the method to execute"""+ return self.generator.exec_task()++ def get_install_path(self, destdir=True):+ """+ Installation path obtained from ``self.dest`` and prefixed by the destdir.+ The variables such as '${PREFIX}/bin' are substituted.+ """+ dest = Utils.subst_vars(self.dest, self.env)+ dest = dest.replace('/', os.sep)+ if destdir and Options.options.destdir:+ dest = os.path.join(Options.options.destdir, os.path.splitdrive(dest)[1].lstrip(os.sep))+ return dest++ def exec_install_files(self):+ """+ Predefined method for installing files+ """+ destpath = self.get_install_path()+ if not destpath:+ raise Errors.WafError('unknown installation path %r' % self.generator)+ for x, y in zip(self.source, self.inputs):+ if self.relative_trick:+ destfile = os.path.join(destpath, y.path_from(self.path))+ Utils.check_dir(os.path.dirname(destfile))+ else:+ destfile = os.path.join(destpath, y.name)+ self.generator.bld.do_install(y.abspath(), destfile, self.chmod)++ def exec_install_as(self):+ """+ Predefined method for installing one file with a given name+ """+ destfile = self.get_install_path()+ self.generator.bld.do_install(self.inputs[0].abspath(), destfile, self.chmod)++ def exec_symlink_as(self):+ """+ Predefined method for installing a symlink+ """+ destfile = self.get_install_path()+ self.generator.bld.do_link(self.link, destfile)++class InstallContext(BuildContext):+ '''installs the targets on the system'''+ cmd = 'install'++ def __init__(self, **kw):+ super(InstallContext, self).__init__(**kw)++ # list of targets to uninstall for removing the empty folders after uninstalling+ self.uninstall = []+ self.is_install = INSTALL++ def do_install(self, src, tgt, chmod=Utils.O644):+ """+ Copy a file from src to tgt with given file permissions. The actual copy is not performed+ if the source and target file have the same size and the same timestamps. When the copy occurs,+ the file is first removed and then copied (prevent stale inodes).++ This method is overridden in :py:meth:`waflib.Build.UninstallContext.do_install` to remove the file.++ :param src: file name as absolute path+ :type src: string+ :param tgt: file destination, as absolute path+ :type tgt: string+ :param chmod: installation mode+ :type chmod: int+ """+ d, _ = os.path.split(tgt)+ if not d:+ raise Errors.WafError('Invalid installation given %r->%r' % (src, tgt))+ Utils.check_dir(d)++ srclbl = src.replace(self.srcnode.abspath() + os.sep, '')+ if not Options.options.force:+ # check if the file is already there to avoid a copy+ try:+ st1 = os.stat(tgt)+ st2 = os.stat(src)+ except OSError:+ pass+ else:+ # same size and identical timestamps -> make no copy+ if st1.st_mtime + 2 >= st2.st_mtime and st1.st_size == st2.st_size:+ if not self.progress_bar:+ Logs.info('- install %s (from %s)' % (tgt, srclbl))+ return False++ if not self.progress_bar:+ Logs.info('+ install %s (from %s)' % (tgt, srclbl))++ # following is for shared libs and stale inodes (-_-)+ try:+ os.remove(tgt)+ except OSError:+ pass++ try:+ shutil.copy2(src, tgt)+ os.chmod(tgt, chmod)+ except IOError:+ try:+ os.stat(src)+ except (OSError, IOError):+ Logs.error('File %r does not exist' % src)+ raise Errors.WafError('Could not install the file %r' % tgt)++ def do_link(self, src, tgt):+ """+ Create a symlink from tgt to src.++ This method is overridden in :py:meth:`waflib.Build.UninstallContext.do_link` to remove the symlink.++ :param src: file name as absolute path+ :type src: string+ :param tgt: file destination, as absolute path+ :type tgt: string+ """+ d, _ = os.path.split(tgt)+ Utils.check_dir(d)++ link = False+ if not os.path.islink(tgt):+ link = True+ elif os.readlink(tgt) != src:+ link = True++ if link:+ try: os.remove(tgt)+ except OSError: pass+ if not self.progress_bar:+ Logs.info('+ symlink %s (to %s)' % (tgt, src))+ os.symlink(src, tgt)+ else:+ if not self.progress_bar:+ Logs.info('- symlink %s (to %s)' % (tgt, src))++ def run_task_now(self, tsk, postpone):+ """+ This method is called by :py:meth:`waflib.Build.InstallContext.install_files`,+ :py:meth:`waflib.Build.InstallContext.install_as` and :py:meth:`waflib.Build.InstallContext.symlink_as` immediately+ after the installation task is created. Its role is to force the immediate execution if necessary, that is when+ ``postpone=False`` was given.+ """+ tsk.post()+ if not postpone:+ if tsk.runnable_status() == Task.ASK_LATER:+ raise self.WafError('cannot post the task %r' % tsk)+ tsk.run()++ def install_files(self, dest, files, env=None, chmod=Utils.O644, relative_trick=False, cwd=None, add=True, postpone=True):+ """+ Create a task to install files on the system::++ def build(bld):+ bld.install_files('${DATADIR}', self.path.find_resource('wscript'))++ :param dest: absolute path of the destination directory+ :type dest: string+ :param files: input files+ :type files: list of strings or list of nodes+ :param env: configuration set for performing substitutions in dest+ :type env: Configuration set+ :param relative_trick: preserve the folder hierarchy when installing whole folders+ :type relative_trick: bool+ :param cwd: parent node for searching srcfile, when srcfile is not a :py:class:`waflib.Node.Node`+ :type cwd: :py:class:`waflib.Node.Node`+ :param add: add the task created to a build group - set ``False`` only if the installation task is created after the build has started+ :type add: bool+ :param postpone: execute the task immediately to perform the installation+ :type postpone: bool+ """+ tsk = inst(env=env or self.env)+ tsk.bld = self+ tsk.path = cwd or self.path+ tsk.chmod = chmod+ if isinstance(files, waflib.Node.Node):+ tsk.source = [files]+ else:+ tsk.source = Utils.to_list(files)+ tsk.dest = dest+ tsk.exec_task = tsk.exec_install_files+ tsk.relative_trick = relative_trick+ if add: self.add_to_group(tsk)+ self.run_task_now(tsk, postpone)+ return tsk++ def install_as(self, dest, srcfile, env=None, chmod=Utils.O644, cwd=None, add=True, postpone=True):+ """+ Create a task to install a file on the system with a different name::++ def build(bld):+ bld.install_as('${PREFIX}/bin', 'myapp', chmod=Utils.O755)++ :param dest: absolute path of the destination file+ :type dest: string+ :param srcfile: input file+ :type srcfile: string or node+ :param cwd: parent node for searching srcfile, when srcfile is not a :py:class:`waflib.Node.Node`+ :type cwd: :py:class:`waflib.Node.Node`+ :param env: configuration set for performing substitutions in dest+ :type env: Configuration set+ :param add: add the task created to a build group - set ``False`` only if the installation task is created after the build has started+ :type add: bool+ :param postpone: execute the task immediately to perform the installation+ :type postpone: bool+ """+ tsk = inst(env=env or self.env)+ tsk.bld = self+ tsk.path = cwd or self.path+ tsk.chmod = chmod+ tsk.source = [srcfile]+ tsk.dest = dest+ tsk.exec_task = tsk.exec_install_as+ if add: self.add_to_group(tsk)+ self.run_task_now(tsk, postpone)+ return tsk++ def symlink_as(self, dest, src, env=None, cwd=None, add=True, postpone=True):+ """+ Create a task to install a symlink::++ def build(bld):+ bld.symlink_as('${PREFIX}/lib/libfoo.so', 'libfoo.so.1.2.3')++ :param dest: absolute path of the symlink+ :type dest: string+ :param src: absolute or relative path of the link+ :type src: string+ :param env: configuration set for performing substitutions in dest+ :type env: Configuration set+ :param add: add the task created to a build group - set ``False`` only if the installation task is created after the build has started+ :type add: bool+ :param postpone: execute the task immediately to perform the installation+ :type postpone: bool+ """++ if Utils.is_win32:+ # symlinks *cannot* work on that platform+ return++ tsk = inst(env=env or self.env)+ tsk.bld = self+ tsk.dest = dest+ tsk.path = cwd or self.path+ tsk.source = []+ tsk.link = src+ tsk.exec_task = tsk.exec_symlink_as+ if add: self.add_to_group(tsk)+ self.run_task_now(tsk, postpone)+ return tsk++class UninstallContext(InstallContext):+ '''removes the targets installed'''+ cmd = 'uninstall'++ def __init__(self, **kw):+ super(UninstallContext, self).__init__(**kw)+ self.is_install = UNINSTALL++ def do_install(self, src, tgt, chmod=Utils.O644):+ """See :py:meth:`waflib.Build.InstallContext.do_install`"""+ if not self.progress_bar:+ Logs.info('- remove %s' % tgt)++ self.uninstall.append(tgt)+ try:+ os.remove(tgt)+ except OSError as e:+ if e.errno != errno.ENOENT:+ if not getattr(self, 'uninstall_error', None):+ self.uninstall_error = True+ Logs.warn('build: some files could not be uninstalled (retry with -vv to list them)')+ if Logs.verbose > 1:+ Logs.warn('Could not remove %s (error code %r)' % (e.filename, e.errno))++ # TODO ita refactor this into a post build action to uninstall the folders (optimization)+ while tgt:+ tgt = os.path.dirname(tgt)+ try:+ os.rmdir(tgt)+ except OSError:+ break++ def do_link(self, src, tgt):+ """See :py:meth:`waflib.Build.InstallContext.do_link`"""+ try:+ if not self.progress_bar:+ Logs.info('- unlink %s' % tgt)+ os.remove(tgt)+ except OSError:+ pass++ # TODO ita refactor this into a post build action to uninstall the folders (optimization)?+ while tgt:+ tgt = os.path.dirname(tgt)+ try:+ os.rmdir(tgt)+ except OSError:+ break++ def execute(self):+ """+ See :py:func:`waflib.Context.Context.execute`+ """+ try:+ # do not execute any tasks+ def runnable_status(self):+ return Task.SKIP_ME+ setattr(Task.Task, 'runnable_status_back', Task.Task.runnable_status)+ setattr(Task.Task, 'runnable_status', runnable_status)++ super(UninstallContext, self).execute()+ finally:+ setattr(Task.Task, 'runnable_status', Task.Task.runnable_status_back)++class CleanContext(BuildContext):+ '''cleans the project'''+ cmd = 'clean'+ def execute(self):+ """+ See :py:func:`waflib.Context.Context.execute`+ """+ self.restore()+ if not self.all_envs:+ self.load_envs()++ self.recurse([self.run_dir])+ try:+ self.clean()+ finally:+ self.store()++ def clean(self):+ """Remove files from the build directory if possible, and reset the caches"""+ Logs.debug('build: clean called')++ if self.bldnode != self.srcnode:+ # would lead to a disaster if top == out+ lst=[]+ for e in self.all_envs.values():+ lst.extend(self.root.find_or_declare(f) for f in e[CFG_FILES])+ for n in self.bldnode.ant_glob('**/*', excl='.lock* *conf_check_*/** config.log c4che/*', quiet=True):+ if n in lst:+ continue+ n.delete()+ self.root.children = {}++ for v in 'node_deps task_sigs raw_deps'.split():+ setattr(self, v, {})++class ListContext(BuildContext):+ '''lists the targets to execute'''++ cmd = 'list'+ def execute(self):+ """+ See :py:func:`waflib.Context.Context.execute`.+ """+ self.restore()+ if not self.all_envs:+ self.load_envs()++ self.recurse([self.run_dir])+ self.pre_build()++ # display the time elapsed in the progress bar+ self.timer = Utils.Timer()++ for g in self.groups:+ for tg in g:+ try:+ f = tg.post+ except AttributeError:+ pass+ else:+ f()++ try:+ # force the cache initialization+ self.get_tgen_by_name('')+ except Exception:+ pass+ lst = list(self.task_gen_cache_names.keys())+ lst.sort()+ for k in lst:+ Logs.pprint('GREEN', k)++class StepContext(BuildContext):+ '''executes tasks in a step-by-step fashion, for debugging'''+ cmd = 'step'++ def __init__(self, **kw):+ super(StepContext, self).__init__(**kw)+ self.files = Options.options.files++ def compile(self):+ """+ Compile the tasks matching the input/output files given (regular expression matching). Derived from :py:meth:`waflib.Build.BuildContext.compile`::++ $ waf step --files=foo.c,bar.c,in:truc.c,out:bar.o+ $ waf step --files=in:foo.cpp.1.o # link task only++ """+ if not self.files:+ Logs.warn('Add a pattern for the debug build, for example "waf step --files=main.c,app"')+ BuildContext.compile(self)+ return++ targets = None+ if self.targets and self.targets != '*':+ targets = self.targets.split(',')++ for g in self.groups:+ for tg in g:+ if targets and tg.name not in targets:+ continue++ try:+ f = tg.post+ except AttributeError:+ pass+ else:+ f()++ for pat in self.files.split(','):+ matcher = self.get_matcher(pat)+ for tg in g:+ if isinstance(tg, Task.TaskBase):+ lst = [tg]+ else:+ lst = tg.tasks+ for tsk in lst:+ do_exec = False+ for node in getattr(tsk, 'inputs', []):+ if matcher(node, output=False):+ do_exec = True+ break+ for node in getattr(tsk, 'outputs', []):+ if matcher(node, output=True):+ do_exec = True+ break+ if do_exec:+ ret = tsk.run()+ Logs.info('%s -> exit %r' % (str(tsk), ret))++ def get_matcher(self, pat):+ # this returns a function+ inn = True+ out = True+ if pat.startswith('in:'):+ out = False+ pat = pat.replace('in:', '')+ elif pat.startswith('out:'):+ inn = False+ pat = pat.replace('out:', '')++ anode = self.root.find_node(pat)+ pattern = None+ if not anode:+ if not pat.startswith('^'):+ pat = '^.+?%s' % pat+ if not pat.endswith('$'):+ pat = '%s$' % pat+ pattern = re.compile(pat)++ def match(node, output):+ if output == True and not out:+ return False+ if output == False and not inn:+ return False++ if anode:+ return anode == node+ else:+ return pattern.match(node.abspath())+ return match++BuildContext.store = Utils.nogc(BuildContext.store)+BuildContext.restore = Utils.nogc(BuildContext.restore)+new file mode 100644@@ -0,0 +1,340 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""++ConfigSet: a special dict++The values put in :py:class:`ConfigSet` must be lists+"""++import copy, re, os+from waflib import Logs, Utils+re_imp = re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$', re.M)++class ConfigSet(object):+ """+ A dict that honor serialization and parent relationships. The serialization format+ is human-readable (python-like) and performed by using eval() and repr().+ For high performance prefer pickle. Do not store functions as they are not serializable.++ The values can be accessed by attributes or by keys::++ from waflib.ConfigSet import ConfigSet+ env = ConfigSet()+ env.FOO = 'test'+ env['FOO'] = 'test'+ """+ __slots__ = ('table', 'parent')+ def __init__(self, filename=None):+ self.table = {}+ """+ Internal dict holding the object values+ """+ #self.parent = None++ if filename:+ self.load(filename)++ def __contains__(self, key):+ """+ Enable the *in* syntax::++ if 'foo' in env:+ print env['foo']+ """+ if key in self.table: return True+ try: return self.parent.__contains__(key)+ except AttributeError: return False # parent may not exist++ def keys(self):+ """Dict interface (unknown purpose)"""+ keys = set()+ cur = self+ while cur:+ keys.update(cur.table.keys())+ cur = getattr(cur, 'parent', None)+ keys = list(keys)+ keys.sort()+ return keys++ def __str__(self):+ """Text representation of the ConfigSet (for debugging purposes)"""+ return "\n".join(["%r %r" % (x, self.__getitem__(x)) for x in self.keys()])++ def __getitem__(self, key):+ """+ Dictionary interface: get value from key::++ def configure(conf):+ conf.env['foo'] = {}+ print(env['foo'])+ """+ try:+ while 1:+ x = self.table.get(key, None)+ if not x is None:+ return x+ self = self.parent+ except AttributeError:+ return []++ def __setitem__(self, key, value):+ """+ Dictionary interface: get value from key+ """+ self.table[key] = value++ def __delitem__(self, key):+ """+ Dictionary interface: get value from key+ """+ self[key] = []++ def __getattr__(self, name):+ """+ Attribute access provided for convenience. The following forms are equivalent::++ def configure(conf):+ conf.env.value+ conf.env['value']+ """+ if name in self.__slots__:+ return object.__getattr__(self, name)+ else:+ return self[name]++ def __setattr__(self, name, value):+ """+ Attribute access provided for convenience. The following forms are equivalent::++ def configure(conf):+ conf.env.value = x+ env['value'] = x+ """+ if name in self.__slots__:+ object.__setattr__(self, name, value)+ else:+ self[name] = value++ def __delattr__(self, name):+ """+ Attribute access provided for convenience. The following forms are equivalent::++ def configure(conf):+ del env.value+ del env['value']+ """+ if name in self.__slots__:+ object.__delattr__(self, name)+ else:+ del self[name]++ def derive(self):+ """+ Returns a new ConfigSet deriving from self. The copy returned+ will be a shallow copy::++ from waflib.ConfigSet import ConfigSet+ env = ConfigSet()+ env.append_value('CFLAGS', ['-O2'])+ child = env.derive()+ child.CFLAGS.append('test') # warning! this will modify 'env'+ child.CFLAGS = ['-O3'] # new list, ok+ child.append_value('CFLAGS', ['-O3']) # ok++ Use :py:func:`ConfigSet.detach` to detach the child from the parent.+ """+ newenv = ConfigSet()+ newenv.parent = self+ return newenv++ def detach(self):+ """+ Detach self from its parent (if existing)++ Modifying the parent :py:class:`ConfigSet` will not change the current object+ Modifying this :py:class:`ConfigSet` will not modify the parent one.+ """+ tbl = self.get_merged_dict()+ try:+ delattr(self, 'parent')+ except AttributeError:+ pass+ else:+ keys = tbl.keys()+ for x in keys:+ tbl[x] = copy.deepcopy(tbl[x])+ self.table = tbl++ def get_flat(self, key):+ """+ Return a value as a string. If the input is a list, the value returned is space-separated.++ :param key: key to use+ :type key: string+ """+ s = self[key]+ if isinstance(s, str): return s+ return ' '.join(s)++ def _get_list_value_for_modification(self, key):+ """+ Return a list value for further modification.++ The list may be modified inplace and there is no need to do this afterwards::++ self.table[var] = value+ """+ try:+ value = self.table[key]+ except KeyError:+ try: value = self.parent[key]+ except AttributeError: value = []+ if isinstance(value, list):+ value = value[:]+ else:+ value = [value]+ else:+ if not isinstance(value, list):+ value = [value]+ self.table[key] = value+ return value++ def append_value(self, var, val):+ """+ Appends a value to the specified config key::++ def build(bld):+ bld.env.append_value('CFLAGS', ['-O2'])++ The value must be a list or a tuple+ """+ current_value = self._get_list_value_for_modification(var)+ if isinstance(val, str): # if there were string everywhere we could optimize this+ val = [val]+ current_value.extend(val)++ def prepend_value(self, var, val):+ """+ Prepends a value to the specified item::++ def configure(conf):+ conf.env.prepend_value('CFLAGS', ['-O2'])++ The value must be a list or a tuple+ """+ if isinstance(val, str):+ val = [val]+ self.table[var] = val + self._get_list_value_for_modification(var)++ def append_unique(self, var, val):+ """+ Append a value to the specified item only if it's not already present::++ def build(bld):+ bld.env.append_unique('CFLAGS', ['-O2', '-g'])++ The value must be a list or a tuple+ """+ if isinstance(val, str):+ val = [val]+ current_value = self._get_list_value_for_modification(var)++ for x in val:+ if x not in current_value:+ current_value.append(x)++ def get_merged_dict(self):+ """+ Compute the merged dictionary from the fusion of self and all its parent++ :rtype: a ConfigSet object+ """+ table_list = []+ env = self+ while 1:+ table_list.insert(0, env.table)+ try: env = env.parent+ except AttributeError: break+ merged_table = {}+ for table in table_list:+ merged_table.update(table)+ return merged_table++ def store(self, filename):+ """+ Write the :py:class:`ConfigSet` data into a file. See :py:meth:`ConfigSet.load` for reading such files.++ :param filename: file to use+ :type filename: string+ """+ try:+ os.makedirs(os.path.split(filename)[0])+ except OSError:+ pass++ f = None+ try:+ f = open(filename, 'w')+ merged_table = self.get_merged_dict()+ keys = list(merged_table.keys())+ keys.sort()+ for k in keys:+ if k != 'undo_stack':+ f.write('%s = %r\n' % (k, merged_table[k]))+ finally:+ if f:+ f.close()++ def load(self, filename):+ """+ Retrieve the :py:class:`ConfigSet` data from a file. See :py:meth:`ConfigSet.store` for writing such files++ :param filename: file to use+ :type filename: string+ """+ tbl = self.table+ code = Utils.readf(filename, m='rU')+ for m in re_imp.finditer(code):+ g = m.group+ tbl[g(2)] = eval(g(3))+ Logs.debug('env: %s' % str(self.table))++ def update(self, d):+ """+ Dictionary interface: replace values from another dict++ :param d: object to use the value from+ :type d: dict-like object+ """+ for k, v in d.items():+ self[k] = v++ def stash(self):+ """+ Store the object state, to provide a kind of transaction support::++ env = ConfigSet()+ env.stash()+ try:+ env.append_value('CFLAGS', '-O3')+ call_some_method(env)+ finally:+ env.revert()++ The history is kept in a stack, and is lost during the serialization by :py:meth:`ConfigSet.store`+ """+ orig = self.table+ tbl = self.table = self.table.copy()+ for x in tbl.keys():+ tbl[x] = copy.deepcopy(tbl[x])+ self.undo_stack = self.undo_stack + [orig]++ def revert(self):+ """+ Reverts the object to a previous state. See :py:meth:`ConfigSet.stash`+ """+ self.table = self.undo_stack.pop(-1)+new file mode 100644@@ -0,0 +1,572 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""+Configuration system++A :py:class:`waflib.Configure.ConfigurationContext` instance is created when ``waf configure`` is called, it is used to:++* create data dictionaries (ConfigSet instances)+* store the list of modules to import+* hold configuration routines such as ``find_program``, etc+"""++import os, shlex, sys, time+from waflib import ConfigSet, Utils, Options, Logs, Context, Build, Errors++try:+ from urllib import request+except ImportError:+ from urllib import urlopen+else:+ urlopen = request.urlopen++BREAK = 'break'+"""In case of a configuration error, break"""++CONTINUE = 'continue'+"""In case of a configuration error, continue"""++WAF_CONFIG_LOG = 'config.log'+"""Name of the configuration log file"""++autoconfig = False+"""Execute the configuration automatically"""++conf_template = '''# project %(app)s configured on %(now)s by+# waf %(wafver)s (abi %(abi)s, python %(pyver)x on %(systype)s)+# using %(args)s+#'''++def download_check(node):+ """+ Hook to check for the tools which are downloaded. Replace with your function if necessary.+ """+ pass++def download_tool(tool, force=False, ctx=None):+ """+ Download a Waf tool from the remote repository defined in :py:const:`waflib.Context.remote_repo`::++ $ waf configure --download+ """+ for x in Utils.to_list(Context.remote_repo):+ for sub in Utils.to_list(Context.remote_locs):+ url = '/'.join((x, sub, tool + '.py'))+ try:+ web = urlopen(url)+ try:+ if web.getcode() != 200:+ continue+ except AttributeError:+ pass+ except Exception:+ # on python3 urlopen throws an exception+ # python 2.3 does not have getcode and throws an exception to fail+ continue+ else:+ tmp = ctx.root.make_node(os.sep.join((Context.waf_dir, 'waflib', 'extras', tool + '.py')))+ tmp.write(web.read(), 'wb')+ Logs.warn('Downloaded %s from %s' % (tool, url))+ download_check(tmp)+ try:+ module = Context.load_tool(tool)+ except Exception:+ Logs.warn('The tool %s from %s is unusable' % (tool, url))+ try:+ tmp.delete()+ except Exception:+ pass+ continue+ return module+ raise Errors.WafError('Could not load the Waf tool')++class ConfigurationContext(Context.Context):+ '''configures the project'''++ cmd = 'configure'++ error_handlers = []+ """+ Additional functions to handle configuration errors+ """++ def __init__(self, **kw):+ super(ConfigurationContext, self).__init__(**kw)+ self.environ = dict(os.environ)+ self.all_envs = {}++ self.top_dir = None+ self.out_dir = None++ self.tools = [] # tools loaded in the configuration, and that will be loaded when building++ self.hash = 0+ self.files = []++ self.tool_cache = []++ self.setenv('')++ def setenv(self, name, env=None):+ """+ Set a new config set for conf.env. If a config set of that name already exists,+ recall it without modification.++ The name is the filename prefix to save to ``c4che/NAME_cache.py``, and it+ is also used as *variants* by the build commands.+ Though related to variants, whatever kind of data may be stored in the config set::++ def configure(cfg):+ cfg.env.ONE = 1+ cfg.setenv('foo')+ cfg.env.ONE = 2++ def build(bld):+ 2 == bld.env_of_name('foo').ONE++ :param name: name of the configuration set+ :type name: string+ :param env: ConfigSet to copy, or an empty ConfigSet is created+ :type env: :py:class:`waflib.ConfigSet.ConfigSet`+ """+ if name not in self.all_envs or env:+ if not env:+ env = ConfigSet.ConfigSet()+ self.prepare_env(env)+ else:+ env = env.derive()+ self.all_envs[name] = env+ self.variant = name++ def get_env(self):+ """Getter for the env property"""+ return self.all_envs[self.variant]+ def set_env(self, val):+ """Setter for the env property"""+ self.all_envs[self.variant] = val++ env = property(get_env, set_env)++ def init_dirs(self):+ """+ Initialize the project directory and the build directory+ """++ top = self.top_dir+ if not top:+ top = Options.options.top+ if not top:+ top = getattr(Context.g_module, Context.TOP, None)+ if not top:+ top = self.path.abspath()+ top = os.path.abspath(top)++ self.srcnode = (os.path.isabs(top) and self.root or self.path).find_dir(top)+ assert(self.srcnode)++ out = self.out_dir+ if not out:+ out = Options.options.out+ if not out:+ out = getattr(Context.g_module, Context.OUT, None)+ if not out:+ out = Options.lockfile.replace('.lock-waf_%s_' % sys.platform, '').replace('.lock-waf', '')++ self.bldnode = (os.path.isabs(out) and self.root or self.path).make_node(out)+ self.bldnode.mkdir()++ if not os.path.isdir(self.bldnode.abspath()):+ conf.fatal('Could not create the build directory %s' % self.bldnode.abspath())++ def execute(self):+ """+ See :py:func:`waflib.Context.Context.execute`+ """+ self.init_dirs()++ self.cachedir = self.bldnode.make_node(Build.CACHE_DIR)+ self.cachedir.mkdir()++ path = os.path.join(self.bldnode.abspath(), WAF_CONFIG_LOG)+ self.logger = Logs.make_logger(path, 'cfg')++ app = getattr(Context.g_module, 'APPNAME', '')+ if app:+ ver = getattr(Context.g_module, 'VERSION', '')+ if ver:+ app = "%s (%s)" % (app, ver)++ now = time.ctime()+ pyver = sys.hexversion+ systype = sys.platform+ args = " ".join(sys.argv)+ wafver = Context.WAFVERSION+ abi = Context.ABI+ self.to_log(conf_template % vars())++ self.msg('Setting top to', self.srcnode.abspath())+ self.msg('Setting out to', self.bldnode.abspath())++ if id(self.srcnode) == id(self.bldnode):+ Logs.warn('Setting top == out (remember to use "update_outputs")')+ elif id(self.path) != id(self.srcnode):+ if self.srcnode.is_child_of(self.path):+ Logs.warn('Are you certain that you do not want to set top="." ?')++ super(ConfigurationContext, self).execute()++ self.store()++ Context.top_dir = self.srcnode.abspath()+ Context.out_dir = self.bldnode.abspath()++ # this will write a configure lock so that subsequent builds will+ # consider the current path as the root directory (see prepare_impl).+ # to remove: use 'waf distclean'+ env = ConfigSet.ConfigSet()+ env['argv'] = sys.argv+ env['options'] = Options.options.__dict__++ env.run_dir = Context.run_dir+ env.top_dir = Context.top_dir+ env.out_dir = Context.out_dir++ # conf.hash & conf.files hold wscript files paths and hash+ # (used only by Configure.autoconfig)+ env['hash'] = self.hash+ env['files'] = self.files+ env['environ'] = dict(self.environ)++ if not self.env.NO_LOCK_IN_RUN:+ env.store(Context.run_dir + os.sep + Options.lockfile)+ if not self.env.NO_LOCK_IN_TOP:+ env.store(Context.top_dir + os.sep + Options.lockfile)+ if not self.env.NO_LOCK_IN_OUT:+ env.store(Context.out_dir + os.sep + Options.lockfile)++ def prepare_env(self, env):+ """+ Insert *PREFIX*, *BINDIR* and *LIBDIR* values into ``env``++ :type env: :py:class:`waflib.ConfigSet.ConfigSet`+ :param env: a ConfigSet, usually ``conf.env``+ """+ if not env.PREFIX:+ if Options.options.prefix or Utils.is_win32:+ env.PREFIX = os.path.abspath(os.path.expanduser(Options.options.prefix))+ else:+ env.PREFIX = ''+ if not env.BINDIR:+ env.BINDIR = Utils.subst_vars('${PREFIX}/bin', env)+ if not env.LIBDIR:+ env.LIBDIR = Utils.subst_vars('${PREFIX}/lib', env)++ def store(self):+ """Save the config results into the cache file"""+ n = self.cachedir.make_node('build.config.py')+ n.write('version = 0x%x\ntools = %r\n' % (Context.HEXVERSION, self.tools))++ if not self.all_envs:+ self.fatal('nothing to store in the configuration context!')++ for key in self.all_envs:+ tmpenv = self.all_envs[key]+ tmpenv.store(os.path.join(self.cachedir.abspath(), key + Build.CACHE_SUFFIX))++ def load(self, input, tooldir=None, funs=None, download=True):+ """+ Load Waf tools, which will be imported whenever a build is started.++ :param input: waf tools to import+ :type input: list of string+ :param tooldir: paths for the imports+ :type tooldir: list of string+ :param funs: functions to execute from the waf tools+ :type funs: list of string+ :param download: whether to download the tool from the waf repository+ :type download: bool+ """++ tools = Utils.to_list(input)+ if tooldir: tooldir = Utils.to_list(tooldir)+ for tool in tools:+ # avoid loading the same tool more than once with the same functions+ # used by composite projects++ mag = (tool, id(self.env), funs)+ if mag in self.tool_cache:+ self.to_log('(tool %s is already loaded, skipping)' % tool)+ continue+ self.tool_cache.append(mag)++ module = None+ try:+ module = Context.load_tool(tool, tooldir)+ except ImportError as e:+ if Options.options.download:+ module = download_tool(tool, ctx=self)+ if not module:+ self.fatal('Could not load the Waf tool %r or download a suitable replacement from the repository (sys.path %r)\n%s' % (tool, sys.path, e))+ else:+ self.fatal('Could not load the Waf tool %r from %r (try the --download option?):\n%s' % (tool, sys.path, e))+ except Exception as e:+ self.to_log('imp %r (%r & %r)' % (tool, tooldir, funs))+ self.to_log(Utils.ex_stack())+ raise++ if funs is not None:+ self.eval_rules(funs)+ else:+ func = getattr(module, 'configure', None)+ if func:+ if type(func) is type(Utils.readf): func(self)+ else: self.eval_rules(func)++ self.tools.append({'tool':tool, 'tooldir':tooldir, 'funs':funs})++ def post_recurse(self, node):+ """+ Records the path and a hash of the scripts visited, see :py:meth:`waflib.Context.Context.post_recurse`++ :param node: script+ :type node: :py:class:`waflib.Node.Node`+ """+ super(ConfigurationContext, self).post_recurse(node)+ self.hash = hash((self.hash, node.read('rb')))+ self.files.append(node.abspath())++ def eval_rules(self, rules):+ """+ Execute the configuration tests. The method :py:meth:`waflib.Configure.ConfigurationContext.err_handler`+ is used to process the eventual exceptions++ :param rules: list of configuration method names+ :type rules: list of string+ """+ self.rules = Utils.to_list(rules)+ for x in self.rules:+ f = getattr(self, x)+ if not f: self.fatal("No such method '%s'." % x)+ try:+ f()+ except Exception as e:+ ret = self.err_handler(x, e)+ if ret == BREAK:+ break+ elif ret == CONTINUE:+ continue+ else:+ raise++ def err_handler(self, fun, error):+ """+ Error handler for the configuration tests, the default is to let the exception raise++ :param fun: configuration test+ :type fun: method+ :param error: exception+ :type error: exception+ """+ pass++def conf(f):+ """+ Decorator: attach new configuration functions to :py:class:`waflib.Build.BuildContext` and+ :py:class:`waflib.Configure.ConfigurationContext`. The methods bound will accept a parameter+ named 'mandatory' to disable the configuration errors::++ def configure(conf):+ conf.find_program('abc', mandatory=False)++ :param f: method to bind+ :type f: function+ """+ def fun(*k, **kw):+ mandatory = True+ if 'mandatory' in kw:+ mandatory = kw['mandatory']+ del kw['mandatory']++ try:+ return f(*k, **kw)+ except Errors.ConfigurationError:+ if mandatory:+ raise++ setattr(ConfigurationContext, f.__name__, fun)+ setattr(Build.BuildContext, f.__name__, fun)+ return f++@conf+def add_os_flags(self, var, dest=None):+ """+ Import operating system environment values into ``conf.env`` dict::++ def configure(conf):+ conf.add_os_flags('CFLAGS')++ :param var: variable to use+ :type var: string+ :param dest: destination variable, by default the same as var+ :type dest: string+ """+ # do not use 'get' to make certain the variable is not defined+ try: self.env.append_value(dest or var, shlex.split(self.environ[var]))+ except KeyError: pass++@conf+def cmd_to_list(self, cmd):+ """+ Detect if a command is written in pseudo shell like ``ccache g++`` and return a list.++ :param cmd: command+ :type cmd: a string or a list of string+ """+ if isinstance(cmd, str) and cmd.find(' '):+ try:+ os.stat(cmd)+ except OSError:+ return shlex.split(cmd)+ else:+ return [cmd]+ return cmd++@conf+def check_waf_version(self, mini='1.6.99', maxi='1.8.0'):+ """+ Raise a Configuration error if the Waf version does not strictly match the given bounds::++ conf.check_waf_version(mini='1.7.0', maxi='1.8.0')++ :type mini: number, tuple or string+ :param mini: Minimum required version+ :type maxi: number, tuple or string+ :param maxi: Maximum allowed version+ """+ self.start_msg('Checking for waf version in %s-%s' % (str(mini), str(maxi)))+ ver = Context.HEXVERSION+ if Utils.num2ver(mini) > ver:+ self.fatal('waf version should be at least %r (%r found)' % (Utils.num2ver(mini), ver))++ if Utils.num2ver(maxi) < ver:+ self.fatal('waf version should be at most %r (%r found)' % (Utils.num2ver(maxi), ver))+ self.end_msg('ok')++@conf+def find_file(self, filename, path_list=[]):+ """+ Find a file in a list of paths++ :param filename: name of the file to search for+ :param path_list: list of directories to search+ :return: the first occurrence filename or '' if filename could not be found+ """+ for n in Utils.to_list(filename):+ for d in Utils.to_list(path_list):+ p = os.path.join(d, n)+ if os.path.exists(p):+ return p+ self.fatal('Could not find %r' % filename)++@conf+def find_program(self, filename, **kw):+ """+ Search for a program on the operating system++ When var is used, you may set os.environ[var] to help find a specific program version, for example::++ $ VALAC=/usr/bin/valac_test waf configure++ :param path_list: paths to use for searching+ :type param_list: list of string+ :param var: store the result to conf.env[var], by default use filename.upper()+ :type var: string+ :param ext: list of extensions for the binary (do not add an extension for portability)+ :type ext: list of string+ """++ exts = kw.get('exts', Utils.is_win32 and '.exe,.com,.bat,.cmd' or ',.sh,.pl,.py')++ environ = kw.get('environ', os.environ)++ ret = ''+ filename = Utils.to_list(filename)++ var = kw.get('var', '')+ if not var:+ var = filename[0].upper()++ if self.env[var]:+ ret = self.env[var]+ elif var in environ:+ ret = environ[var]++ path_list = kw.get('path_list', '')+ if not ret:+ if path_list:+ path_list = Utils.to_list(path_list)+ else:+ path_list = environ.get('PATH', '').split(os.pathsep)++ if not isinstance(filename, list):+ filename = [filename]++ for a in exts.split(','):+ if ret:+ break+ for b in filename:+ if ret:+ break+ for c in path_list:+ if ret:+ break+ x = os.path.expanduser(os.path.join(c, b + a))+ if os.path.isfile(x):+ ret = x++ if not ret and Utils.winreg:+ ret = Utils.get_registry_app_path(Utils.winreg.HKEY_CURRENT_USER, filename)+ if not ret and Utils.winreg:+ ret = Utils.get_registry_app_path(Utils.winreg.HKEY_LOCAL_MACHINE, filename)++ self.msg('Checking for program ' + ','.join(filename), ret or False)+ self.to_log('find program=%r paths=%r var=%r -> %r' % (filename, path_list, var, ret))++ if not ret:+ self.fatal(kw.get('errmsg', '') or 'Could not find the program %s' % ','.join(filename))++ if var:+ self.env[var] = ret+ return ret+++@conf+def find_perl_program(self, filename, path_list=[], var=None, environ=None, exts=''):+ """+ Search for a perl program on the operating system++ :param filename: file to search for+ :type filename: string+ :param path_list: list of paths to look into+ :type path_list: list of string+ :param var: store the results into *conf.env.var*+ :type var: string+ :param environ: operating system environment to pass to :py:func:`waflib.Configure.find_program`+ :type environ: dict+ :param exts: extensions given to :py:func:`waflib.Configure.find_program`+ :type exts: list+ """++ try:+ app = self.find_program(filename, path_list=path_list, var=var, environ=environ, exts=exts)+ except Exception:+ self.find_program('perl', var='PERL')+ app = self.find_file(filename, os.environ['PATH'].split(os.pathsep))+ if not app:+ raise+ if var:+ self.env[var] = Utils.to_list(self.env['PERL']) + [app]+ self.msg('Checking for %r' % filename, app)+new file mode 100644@@ -0,0 +1,617 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010 (ita)++"""+Classes and functions required for waf commands+"""++import os, imp, sys+from waflib import Utils, Errors, Logs+import waflib.Node++# the following 3 constants are updated on each new release (do not touch)+HEXVERSION=0x1070600+"""Constant updated on new releases"""++WAFVERSION="1.7.6"+"""Constant updated on new releases"""++WAFREVISION="704f85f131c77b2244eaf134afe8fe04373d3707"+"""Constant updated on new releases"""++ABI = 98+"""Version of the build data cache file format (used in :py:const:`waflib.Context.DBFILE`)"""++DBFILE = '.wafpickle-%s-%d-%d' % (sys.platform, sys.hexversion, ABI)+"""Name of the pickle file for storing the build data"""++APPNAME = 'APPNAME'+"""Default application name (used by ``waf dist``)"""++VERSION = 'VERSION'+"""Default application version (used by ``waf dist``)"""++TOP = 'top'+"""The variable name for the top-level directory in wscript files"""++OUT = 'out'+"""The variable name for the output directory in wscript files"""++WSCRIPT_FILE = 'wscript'+"""Name of the waf script files"""+++launch_dir = ''+"""Directory from which waf has been called"""+run_dir = ''+"""Location of the wscript file to use as the entry point"""+top_dir = ''+"""Location of the project directory (top), if the project was configured"""+out_dir = ''+"""Location of the build directory (out), if the project was configured"""+waf_dir = ''+"""Directory containing the waf modules"""++local_repo = ''+"""Local repository containing additional Waf tools (plugins)"""+remote_repo = 'http://waf.googlecode.com/git/'+"""+Remote directory containing downloadable waf tools. The missing tools can be downloaded by using::++ $ waf configure --download+"""++remote_locs = ['waflib/extras', 'waflib/Tools']+"""+Remote directories for use with :py:const:`waflib.Context.remote_repo`+"""++g_module = None+"""+Module representing the main wscript file (see :py:const:`waflib.Context.run_dir`)+"""++STDOUT = 1+STDERR = -1+BOTH = 0++classes = []+"""+List of :py:class:`waflib.Context.Context` subclasses that can be used as waf commands. The classes+are added automatically by a metaclass.+"""+++def create_context(cmd_name, *k, **kw):+ """+ Create a new :py:class:`waflib.Context.Context` instance corresponding to the given command.+ Used in particular by :py:func:`waflib.Scripting.run_command`++ :param cmd_name: command+ :type cmd_name: string+ :param k: arguments to give to the context class initializer+ :type k: list+ :param k: keyword arguments to give to the context class initializer+ :type k: dict+ """+ global classes+ for x in classes:+ if x.cmd == cmd_name:+ return x(*k, **kw)+ ctx = Context(*k, **kw)+ ctx.fun = cmd_name+ return ctx++class store_context(type):+ """+ Metaclass for storing the command classes into the list :py:const:`waflib.Context.classes`+ Context classes must provide an attribute 'cmd' representing the command to execute+ """+ def __init__(cls, name, bases, dict):+ super(store_context, cls).__init__(name, bases, dict)+ name = cls.__name__++ if name == 'ctx' or name == 'Context':+ return++ try:+ cls.cmd+ except AttributeError:+ raise Errors.WafError('Missing command for the context class %r (cmd)' % name)++ if not getattr(cls, 'fun', None):+ cls.fun = cls.cmd++ global classes+ classes.insert(0, cls)++ctx = store_context('ctx', (object,), {})+"""Base class for the :py:class:`waflib.Context.Context` classes"""++class Context(ctx):+ """+ Default context for waf commands, and base class for new command contexts.++ Context objects are passed to top-level functions::++ def foo(ctx):+ print(ctx.__class__.__name__) # waflib.Context.Context++ Subclasses must define the attribute 'cmd':++ :param cmd: command to execute as in ``waf cmd``+ :type cmd: string+ :param fun: function name to execute when the command is called+ :type fun: string++ .. inheritance-diagram:: waflib.Context.Context waflib.Build.BuildContext waflib.Build.InstallContext waflib.Build.UninstallContext waflib.Build.StepContext waflib.Build.ListContext waflib.Configure.ConfigurationContext waflib.Scripting.Dist waflib.Scripting.DistCheck waflib.Build.CleanContext++ """++ errors = Errors+ """+ Shortcut to :py:mod:`waflib.Errors` provided for convenience+ """++ tools = {}+ """+ A cache for modules (wscript files) read by :py:meth:`Context.Context.load`+ """++ def __init__(self, **kw):+ try:+ rd = kw['run_dir']+ except KeyError:+ global run_dir+ rd = run_dir++ # binds the context to the nodes in use to avoid a context singleton+ class node_class(waflib.Node.Node):+ pass+ self.node_class = node_class+ self.node_class.__module__ = "waflib.Node"+ self.node_class.__name__ = "Nod3"+ self.node_class.ctx = self++ self.root = self.node_class('', None)+ self.cur_script = None+ self.path = self.root.find_dir(rd)++ self.stack_path = []+ self.exec_dict = {'ctx':self, 'conf':self, 'bld':self, 'opt':self}+ self.logger = None++ def __hash__(self):+ """+ Return a hash value for storing context objects in dicts or sets. The value is not persistent.++ :return: hash value+ :rtype: int+ """+ return id(self)++ def load(self, tool_list, *k, **kw):+ """+ Load a Waf tool as a module, and try calling the function named :py:const:`waflib.Context.Context.fun` from it.+ A ``tooldir`` value may be provided as a list of module paths.++ :type tool_list: list of string or space-separated string+ :param tool_list: list of Waf tools to use+ """+ tools = Utils.to_list(tool_list)+ path = Utils.to_list(kw.get('tooldir', ''))++ for t in tools:+ module = load_tool(t, path)+ fun = getattr(module, kw.get('name', self.fun), None)+ if fun:+ fun(self)++ def execute(self):+ """+ Execute the command. Redefine this method in subclasses.+ """+ global g_module+ self.recurse([os.path.dirname(g_module.root_path)])++ def pre_recurse(self, node):+ """+ Method executed immediately before a folder is read by :py:meth:`waflib.Context.Context.recurse`. The node given is set+ as an attribute ``self.cur_script``, and as the current path ``self.path``++ :param node: script+ :type node: :py:class:`waflib.Node.Node`+ """+ self.stack_path.append(self.cur_script)++ self.cur_script = node+ self.path = node.parent++ def post_recurse(self, node):+ """+ Restore ``self.cur_script`` and ``self.path`` right after :py:meth:`waflib.Context.Context.recurse` terminates.++ :param node: script+ :type node: :py:class:`waflib.Node.Node`+ """+ self.cur_script = self.stack_path.pop()+ if self.cur_script:+ self.path = self.cur_script.parent++ def recurse(self, dirs, name=None, mandatory=True, once=True):+ """+ Run user code from the supplied list of directories.+ The directories can be either absolute, or relative to the directory+ of the wscript file. The methods :py:meth:`waflib.Context.Context.pre_recurse` and :py:meth:`waflib.Context.Context.post_recurse`+ are called immediately before and after a script has been executed.++ :param dirs: List of directories to visit+ :type dirs: list of string or space-separated string+ :param name: Name of function to invoke from the wscript+ :type name: string+ :param mandatory: whether sub wscript files are required to exist+ :type mandatory: bool+ :param once: read the script file once for a particular context+ :type once: bool+ """+ try:+ cache = self.recurse_cache+ except AttributeError:+ cache = self.recurse_cache = {}++ for d in Utils.to_list(dirs):++ if not os.path.isabs(d):+ # absolute paths only+ d = os.path.join(self.path.abspath(), d)++ WSCRIPT = os.path.join(d, WSCRIPT_FILE)+ WSCRIPT_FUN = WSCRIPT + '_' + (name or self.fun)++ node = self.root.find_node(WSCRIPT_FUN)+ if node and (not once or node not in cache):+ cache[node] = True+ self.pre_recurse(node)+ try:+ function_code = node.read('rU')+ exec(compile(function_code, node.abspath(), 'exec'), self.exec_dict)+ finally:+ self.post_recurse(node)+ elif not node:+ node = self.root.find_node(WSCRIPT)+ tup = (node, name or self.fun)+ if node and (not once or tup not in cache):+ cache[tup] = True+ self.pre_recurse(node)+ try:+ wscript_module = load_module(node.abspath())+ user_function = getattr(wscript_module, (name or self.fun), None)+ if not user_function:+ if not mandatory:+ continue+ raise Errors.WafError('No function %s defined in %s' % (name or self.fun, node.abspath()))+ user_function(self)+ finally:+ self.post_recurse(node)+ elif not node:+ if not mandatory:+ continue+ raise Errors.WafError('No wscript file in directory %s' % d)++ def exec_command(self, cmd, **kw):+ """+ Execute a command and return the exit status. If the context has the attribute 'log',+ capture and log the process stderr/stdout for logging purposes::++ def run(tsk):+ ret = tsk.generator.bld.exec_command('touch foo.txt')+ return ret++ This method captures the standard/error outputs (Issue 1101), but it does not return the values+ unlike :py:meth:`waflib.Context.Context.cmd_and_log`++ :param cmd: command argument for subprocess.Popen+ :param kw: keyword arguments for subprocess.Popen+ """+ subprocess = Utils.subprocess+ kw['shell'] = isinstance(cmd, str)+ Logs.debug('runner: %r' % cmd)+ Logs.debug('runner_env: kw=%s' % kw)++ if self.logger:+ self.logger.info(cmd)++ if 'stdout' not in kw:+ kw['stdout'] = subprocess.PIPE+ if 'stderr' not in kw:+ kw['stderr'] = subprocess.PIPE++ try:+ if kw['stdout'] or kw['stderr']:+ p = subprocess.Popen(cmd, **kw)+ (out, err) = p.communicate()+ ret = p.returncode+ else:+ out, err = (None, None)+ ret = subprocess.Popen(cmd, **kw).wait()+ except Exception as e:+ raise Errors.WafError('Execution failure: %s' % str(e), ex=e)++ if out:+ if not isinstance(out, str):+ out = out.decode(sys.stdout.encoding or 'iso8859-1')+ if self.logger:+ self.logger.debug('out: %s' % out)+ else:+ sys.stdout.write(out)+ if err:+ if not isinstance(err, str):+ err = err.decode(sys.stdout.encoding or 'iso8859-1')+ if self.logger:+ self.logger.error('err: %s' % err)+ else:+ sys.stderr.write(err)++ return ret++ def cmd_and_log(self, cmd, **kw):+ """+ Execute a command and return stdout if the execution is successful.+ An exception is thrown when the exit status is non-0. In that case, both stderr and stdout+ will be bound to the WafError object::++ def configure(conf):+ out = conf.cmd_and_log(['echo', 'hello'], output=waflib.Context.STDOUT, quiet=waflib.Context.BOTH)+ (out, err) = conf.cmd_and_log(['echo', 'hello'], output=waflib.Context.BOTH)+ try:+ conf.cmd_and_log(['which', 'someapp'], output=waflib.Context.BOTH)+ except Exception as e:+ print(e.stdout, e.stderr)++ :param cmd: args for subprocess.Popen+ :param kw: keyword arguments for subprocess.Popen+ """+ subprocess = Utils.subprocess+ kw['shell'] = isinstance(cmd, str)+ Logs.debug('runner: %r' % cmd)++ if 'quiet' in kw:+ quiet = kw['quiet']+ del kw['quiet']+ else:+ quiet = None++ if 'output' in kw:+ to_ret = kw['output']+ del kw['output']+ else:+ to_ret = STDOUT++ kw['stdout'] = kw['stderr'] = subprocess.PIPE+ if quiet is None:+ self.to_log(cmd)+ try:+ p = subprocess.Popen(cmd, **kw)+ (out, err) = p.communicate()+ except Exception as e:+ raise Errors.WafError('Execution failure: %s' % str(e), ex=e)++ if not isinstance(out, str):+ out = out.decode(sys.stdout.encoding or 'iso8859-1')+ if not isinstance(err, str):+ err = err.decode(sys.stdout.encoding or 'iso8859-1')++ if out and quiet != STDOUT and quiet != BOTH:+ self.to_log('out: %s' % out)+ if err and quiet != STDERR and quiet != BOTH:+ self.to_log('err: %s' % err)++ if p.returncode:+ e = Errors.WafError('Command %r returned %r' % (cmd, p.returncode))+ e.returncode = p.returncode+ e.stderr = err+ e.stdout = out+ raise e++ if to_ret == BOTH:+ return (out, err)+ elif to_ret == STDERR:+ return err+ return out++ def fatal(self, msg, ex=None):+ """+ Raise a configuration error to interrupt the execution immediately::++ def configure(conf):+ conf.fatal('a requirement is missing')++ :param msg: message to display+ :type msg: string+ :param ex: optional exception object+ :type ex: exception+ """+ if self.logger:+ self.logger.info('from %s: %s' % (self.path.abspath(), msg))+ try:+ msg = '%s\n(complete log in %s)' % (msg, self.logger.handlers[0].baseFilename)+ except Exception:+ pass+ raise self.errors.ConfigurationError(msg, ex=ex)++ def to_log(self, msg):+ """+ Log some information to the logger (if present), or to stderr. If the message is empty,+ it is not printed::++ def build(bld):+ bld.to_log('starting the build')++ When in doubt, override this method, or provide a logger on the context class.++ :param msg: message+ :type msg: string+ """+ if not msg:+ return+ if self.logger:+ self.logger.info(msg)+ else:+ sys.stderr.write(str(msg))+ sys.stderr.flush()+++ def msg(self, msg, result, color=None):+ """+ Print a configuration message of the form ``msg: result``.+ The second part of the message will be in colors. The output+ can be disabled easly by setting ``in_msg`` to a positive value::++ def configure(conf):+ self.in_msg = 1+ conf.msg('Checking for library foo', 'ok')+ # no output++ :param msg: message to display to the user+ :type msg: string+ :param result: result to display+ :type result: string or boolean+ :param color: color to use, see :py:const:`waflib.Logs.colors_lst`+ :type color: string+ """+ self.start_msg(msg)++ if not isinstance(color, str):+ color = result and 'GREEN' or 'YELLOW'++ self.end_msg(result, color)++ def start_msg(self, msg):+ """+ Print the beginning of a 'Checking for xxx' message. See :py:meth:`waflib.Context.Context.msg`+ """+ try:+ if self.in_msg:+ self.in_msg += 1+ return+ except AttributeError:+ self.in_msg = 0+ self.in_msg += 1++ try:+ self.line_just = max(self.line_just, len(msg))+ except AttributeError:+ self.line_just = max(40, len(msg))+ for x in (self.line_just * '-', msg):+ self.to_log(x)+ Logs.pprint('NORMAL', "%s :" % msg.ljust(self.line_just), sep='')++ def end_msg(self, result, color=None):+ """Print the end of a 'Checking for' message. See :py:meth:`waflib.Context.Context.msg`"""+ self.in_msg -= 1+ if self.in_msg:+ return++ defcolor = 'GREEN'+ if result == True:+ msg = 'ok'+ elif result == False:+ msg = 'not found'+ defcolor = 'YELLOW'+ else:+ msg = str(result)++ self.to_log(msg)+ Logs.pprint(color or defcolor, msg)+++ def load_special_tools(self, var, ban=[]):+ global waf_dir+ lst = self.root.find_node(waf_dir).find_node('waflib/extras').ant_glob(var)+ for x in lst:+ if not x.name in ban:+ load_tool(x.name.replace('.py', ''))++cache_modules = {}+"""+Dictionary holding already loaded modules, keyed by their absolute path.+The modules are added automatically by :py:func:`waflib.Context.load_module`+"""++def load_module(path):+ """+ Load a source file as a python module.++ :param path: file path+ :type path: string+ :return: Loaded Python module+ :rtype: module+ """+ try:+ return cache_modules[path]+ except KeyError:+ pass++ module = imp.new_module(WSCRIPT_FILE)+ try:+ code = Utils.readf(path, m='rU')+ except (IOError, OSError):+ raise Errors.WafError('Could not read the file %r' % path)++ module_dir = os.path.dirname(path)+ sys.path.insert(0, module_dir)++ exec(compile(code, path, 'exec'), module.__dict__)+ sys.path.remove(module_dir)++ cache_modules[path] = module++ return module++def load_tool(tool, tooldir=None):+ """+ Import a Waf tool (python module), and store it in the dict :py:const:`waflib.Context.Context.tools`++ :type tool: string+ :param tool: Name of the tool+ :type tooldir: list+ :param tooldir: List of directories to search for the tool module+ """+ if tool == 'java':+ tool = 'javaw' # jython+ elif tool == 'compiler_cc':+ tool = 'compiler_c' # TODO remove in waf 1.8+ else:+ tool = tool.replace('++', 'xx')++ if tooldir:+ assert isinstance(tooldir, list)+ sys.path = tooldir + sys.path+ try:+ __import__(tool)+ ret = sys.modules[tool]+ Context.tools[tool] = ret+ return ret+ finally:+ for d in tooldir:+ sys.path.remove(d)+ else:+ global waf_dir+ try:+ os.stat(os.path.join(waf_dir, 'waflib', 'extras', tool + '.py'))+ except OSError:+ try:+ os.stat(os.path.join(waf_dir, 'waflib', 'Tools', tool + '.py'))+ except OSError:+ d = tool # user has messed with sys.path+ else:+ d = 'waflib.Tools.%s' % tool+ else:+ d = 'waflib.extras.%s' % tool++ __import__(d)+ ret = sys.modules[d]+ Context.tools[tool] = ret+ return ret+new file mode 100644@@ -0,0 +1,70 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010 (ita)++"""+Exceptions used in the Waf code+"""++import traceback, sys++class WafError(Exception):+ """Base class for all Waf errors"""+ def __init__(self, msg='', ex=None):+ """+ :param msg: error message+ :type msg: string+ :param ex: exception causing this error (optional)+ :type ex: exception+ """+ self.msg = msg+ assert not isinstance(msg, Exception)++ self.stack = []+ if ex:+ if not msg:+ self.msg = str(ex)+ if isinstance(ex, WafError):+ self.stack = ex.stack+ else:+ self.stack = traceback.extract_tb(sys.exc_info()[2])+ self.stack += traceback.extract_stack()[:-1]+ self.verbose_msg = ''.join(traceback.format_list(self.stack))++ def __str__(self):+ return str(self.msg)++class BuildError(WafError):+ """+ Errors raised during the build and install phases+ """+ def __init__(self, error_tasks=[]):+ """+ :param error_tasks: tasks that could not complete normally+ :type error_tasks: list of task objects+ """+ self.tasks = error_tasks+ WafError.__init__(self, self.format_error())++ def format_error(self):+ """format the error messages from the tasks that failed"""+ lst = ['Build failed']+ for tsk in self.tasks:+ txt = tsk.format_error()+ if txt: lst.append(txt)+ return '\n'.join(lst)++class ConfigurationError(WafError):+ """+ Configuration exception raised in particular by :py:meth:`waflib.Context.Context.fatal`+ """+ pass++class TaskRescan(WafError):+ """task-specific exception type, trigger a signature recomputation"""+ pass++class TaskNotReady(WafError):+ """task-specific exception type, raised when the task signature cannot be computed"""+ pass+new file mode 100644@@ -0,0 +1,307 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""+logging, colors, terminal width and pretty-print+"""++import os, re, traceback, sys++try:+ import threading+except ImportError:+ pass+else:+ wlock = threading.Lock()++ class sync_stream(object):+ def __init__(self, stream):+ self.stream = stream+ self.encoding = self.stream.encoding++ def write(self, txt):+ try:+ wlock.acquire()+ self.stream.write(txt)+ self.stream.flush()+ finally:+ wlock.release()++ def fileno(self):+ return self.stream.fileno()++ def flush(self):+ self.stream.flush()++ def isatty(self):+ return self.stream.isatty()++ _nocolor = os.environ.get('NOCOLOR', 'no') not in ('no', '0', 'false')+ try:+ if not _nocolor:+ import waflib.ansiterm+ except ImportError:+ pass++ if not os.environ.get('NOSYNC', False):+ if id(sys.stdout) == id(sys.__stdout__):+ sys.stdout = sync_stream(sys.stdout)+ sys.stderr = sync_stream(sys.stderr)++import logging # import other modules only after++LOG_FORMAT = "%(asctime)s %(c1)s%(zone)s%(c2)s %(message)s"+HOUR_FORMAT = "%H:%M:%S"++zones = ''+verbose = 0++colors_lst = {+'USE' : True,+'BOLD' :'\x1b[01;1m',+'RED' :'\x1b[01;31m',+'GREEN' :'\x1b[32m',+'YELLOW':'\x1b[33m',+'PINK' :'\x1b[35m',+'BLUE' :'\x1b[01;34m',+'CYAN' :'\x1b[36m',+'NORMAL':'\x1b[0m',+'cursor_on' :'\x1b[?25h',+'cursor_off' :'\x1b[?25l',+}++got_tty = not os.environ.get('TERM', 'dumb') in ['dumb', 'emacs']+if got_tty:+ try:+ got_tty = sys.stderr.isatty() and sys.stdout.isatty()+ except AttributeError:+ got_tty = False++if (not got_tty and os.environ.get('TERM', 'dumb') != 'msys') or _nocolor:+ colors_lst['USE'] = False++def get_term_cols():+ return 80++# If console packages are available, replace the dummy function with a real+# implementation+try:+ import struct, fcntl, termios+except ImportError:+ pass+else:+ if got_tty:+ def get_term_cols_real():+ """+ Private use only.+ """++ dummy_lines, cols = struct.unpack("HHHH", \+ fcntl.ioctl(sys.stderr.fileno(),termios.TIOCGWINSZ , \+ struct.pack("HHHH", 0, 0, 0, 0)))[:2]+ return cols+ # try the function once to see if it really works+ try:+ get_term_cols_real()+ except Exception:+ pass+ else:+ get_term_cols = get_term_cols_real++get_term_cols.__doc__ = """+ Get the console width in characters.++ :return: the number of characters per line+ :rtype: int+ """++def get_color(cl):+ if not colors_lst['USE']: return ''+ return colors_lst.get(cl, '')++class color_dict(object):+ """attribute-based color access, eg: colors.PINK"""+ def __getattr__(self, a):+ return get_color(a)+ def __call__(self, a):+ return get_color(a)++colors = color_dict()++re_log = re.compile(r'(\w+): (.*)', re.M)+class log_filter(logging.Filter):+ """+ The waf logs are of the form 'name: message', and can be filtered by 'waf --zones=name'.+ For example, the following::++ from waflib import Logs+ Logs.debug('test: here is a message')++ Will be displayed only when executing::++ $ waf --zones=test+ """+ def __init__(self, name=None):+ pass++ def filter(self, rec):+ """+ filter a record, adding the colors automatically++ * error: red+ * warning: yellow++ :param rec: message to record+ """++ rec.c1 = colors.PINK+ rec.c2 = colors.NORMAL+ rec.zone = rec.module+ if rec.levelno >= logging.INFO:+ if rec.levelno >= logging.ERROR:+ rec.c1 = colors.RED+ elif rec.levelno >= logging.WARNING:+ rec.c1 = colors.YELLOW+ else:+ rec.c1 = colors.GREEN+ return True++ m = re_log.match(rec.msg)+ if m:+ rec.zone = m.group(1)+ rec.msg = m.group(2)++ if zones:+ return getattr(rec, 'zone', '') in zones or '*' in zones+ elif not verbose > 2:+ return False+ return True++class formatter(logging.Formatter):+ """Simple log formatter which handles colors"""+ def __init__(self):+ logging.Formatter.__init__(self, LOG_FORMAT, HOUR_FORMAT)++ def format(self, rec):+ """Messages in warning, error or info mode are displayed in color by default"""+ if rec.levelno >= logging.WARNING or rec.levelno == logging.INFO:+ try:+ msg = rec.msg.decode('utf-8')+ except Exception:+ msg = rec.msg+ return '%s%s%s' % (rec.c1, msg, rec.c2)+ return logging.Formatter.format(self, rec)++log = None+"""global logger for Logs.debug, Logs.error, etc"""++def debug(*k, **kw):+ """+ Wrap logging.debug, the output is filtered for performance reasons+ """+ if verbose:+ k = list(k)+ k[0] = k[0].replace('\n', ' ')+ global log+ log.debug(*k, **kw)++def error(*k, **kw):+ """+ Wrap logging.errors, display the origin of the message when '-vv' is set+ """+ global log+ log.error(*k, **kw)+ if verbose > 2:+ st = traceback.extract_stack()+ if st:+ st = st[:-1]+ buf = []+ for filename, lineno, name, line in st:+ buf.append(' File "%s", line %d, in %s' % (filename, lineno, name))+ if line:+ buf.append(' %s' % line.strip())+ if buf: log.error("\n".join(buf))++def warn(*k, **kw):+ """+ Wrap logging.warn+ """+ global log+ log.warn(*k, **kw)++def info(*k, **kw):+ """+ Wrap logging.info+ """+ global log+ log.info(*k, **kw)++def init_log():+ """+ Initialize the loggers globally+ """+ global log+ log = logging.getLogger('waflib')+ log.handlers = []+ log.filters = []+ hdlr = logging.StreamHandler()+ hdlr.setFormatter(formatter())+ log.addHandler(hdlr)+ log.addFilter(log_filter())+ log.setLevel(logging.DEBUG)++def make_logger(path, name):+ """+ Create a simple logger, which is often used to redirect the context command output::++ from waflib import Logs+ bld.logger = Logs.make_logger('test.log', 'build')+ bld.check(header_name='sadlib.h', features='cxx cprogram', mandatory=False)+ bld.logger = None++ :param path: file name to write the log output to+ :type path: string+ :param name: logger name (loggers are reused)+ :type name: string+ """+ logger = logging.getLogger(name)+ hdlr = logging.FileHandler(path, 'w')+ formatter = logging.Formatter('%(message)s')+ hdlr.setFormatter(formatter)+ logger.addHandler(hdlr)+ logger.setLevel(logging.DEBUG)+ return logger++def make_mem_logger(name, to_log, size=10000):+ """+ Create a memory logger to avoid writing concurrently to the main logger+ """+ from logging.handlers import MemoryHandler+ logger = logging.getLogger(name)+ hdlr = MemoryHandler(size, target=to_log)+ formatter = logging.Formatter('%(message)s')+ hdlr.setFormatter(formatter)+ logger.addHandler(hdlr)+ logger.memhandler = hdlr+ logger.setLevel(logging.DEBUG)+ return logger++def pprint(col, str, label='', sep='\n'):+ """+ Print messages in color immediately on stderr::++ from waflib import Logs+ Logs.pprint('RED', 'Something bad just happened')++ :param col: color name to use in :py:const:`Logs.colors_lst`+ :type col: string+ :param str: message to display+ :type str: string or a value that can be printed by %s+ :param label: a message to add after the colored output+ :type label: string+ :param sep: a string to append at the end (line separator)+ :type sep: string+ """+ sys.stderr.write("%s%s%s %s%s" % (colors(col), str, colors.NORMAL, label, sep))+new file mode 100644@@ -0,0 +1,811 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""+Node: filesystem structure, contains lists of nodes++#. Each file/folder is represented by exactly one node.++#. Some potential class properties are stored on :py:class:`waflib.Build.BuildContext` : nodes to depend on, etc.+ Unused class members can increase the `.wafpickle` file size sensibly.++#. Node objects should never be created directly, use+ the methods :py:func:`Node.make_node` or :py:func:`Node.find_node`++#. The methods :py:func:`Node.find_resource`, :py:func:`Node.find_dir` :py:func:`Node.find_or_declare` should be+ used when a build context is present++#. Each instance of :py:class:`waflib.Context.Context` has a unique :py:class:`Node` subclass.+ (:py:class:`waflib.Node.Nod3`, see the :py:class:`waflib.Context.Context` initializer). A reference to the context owning a node is held as self.ctx+"""++import os, re, sys, shutil+from waflib import Utils, Errors++exclude_regs = '''+**/*~+**/#*#+**/.#*+**/%*%+**/._*+**/CVS+**/CVS/**+**/.cvsignore+**/SCCS+**/SCCS/**+**/vssver.scc+**/.svn+**/.svn/**+**/BitKeeper+**/.git+**/.git/**+**/.gitignore+**/.bzr+**/.bzrignore+**/.bzr/**+**/.hg+**/.hg/**+**/_MTN+**/_MTN/**+**/.arch-ids+**/{arch}+**/_darcs+**/_darcs/**+**/.DS_Store'''+"""+Ant patterns for files and folders to exclude while doing the+recursive traversal in :py:meth:`waflib.Node.Node.ant_glob`+"""++def split_path(path):+ """+ Split a path by os.sep (This is not os.path.split)++ :param path: path to split+ :type path: string+ :rtype: list of string+ :return: the path, split+ """+ return path.split('/')++def split_path_cygwin(path):+ if path.startswith('//'):+ ret = path.split('/')[2:]+ ret[0] = '/' + ret[0]+ return ret+ return path.split('/')++re_sp = re.compile('[/\\\\]')+def split_path_win32(path):+ if path.startswith('\\\\'):+ ret = re.split(re_sp, path)[2:]+ ret[0] = '\\' + ret[0]+ return ret+ return re.split(re_sp, path)++if sys.platform == 'cygwin':+ split_path = split_path_cygwin+elif Utils.is_win32:+ split_path = split_path_win32++class Node(object):+ """+ This class is organized in two parts++ * The basic methods meant for filesystem access (compute paths, create folders, etc)+ * The methods bound to a :py:class:`waflib.Build.BuildContext` (require ``bld.srcnode`` and ``bld.bldnode``)++ The Node objects are not thread safe in any way.+ """++ __slots__ = ('name', 'sig', 'children', 'parent', 'cache_abspath', 'cache_isdir', 'cache_sig')+ def __init__(self, name, parent):+ self.name = name+ self.parent = parent++ if parent:+ if name in parent.children:+ raise Errors.WafError('node %s exists in the parent files %r already' % (name, parent))+ parent.children[name] = self++ def __setstate__(self, data):+ "Deserializes from data"+ self.name = data[0]+ self.parent = data[1]+ if data[2] is not None:+ self.children = data[2]+ if data[3] is not None:+ self.sig = data[3]++ def __getstate__(self):+ "Serialize the node info"+ return (self.name, self.parent, getattr(self, 'children', None), getattr(self, 'sig', None))++ def __str__(self):+ "String representation (name), for debugging purposes"+ return self.name++ def __repr__(self):+ "String representation (abspath), for debugging purposes"+ return self.abspath()++ def __hash__(self):+ "Node hash, used for storage in dicts. This hash is not persistent."+ return id(self)++ def __eq__(self, node):+ "Node comparison, based on the IDs"+ return id(self) == id(node)++ def __copy__(self):+ "Implemented to prevent nodes from being copied (raises an exception)"+ raise Errors.WafError('nodes are not supposed to be copied')++ def read(self, flags='r', encoding='ISO8859-1'):+ """+ Return the contents of the file represented by this node::++ def build(bld):+ bld.path.find_node('wscript').read()++ :type fname: string+ :param fname: Path to file+ :type m: string+ :param m: Open mode+ :rtype: string+ :return: File contents+ """+ return Utils.readf(self.abspath(), flags, encoding)++ def write(self, data, flags='w', encoding='ISO8859-1'):+ """+ Write some text to the physical file represented by this node::++ def build(bld):+ bld.path.make_node('foo.txt').write('Hello, world!')++ :type data: string+ :param data: data to write+ :type flags: string+ :param flags: Write mode+ """+ Utils.writef(self.abspath(), data, flags, encoding)++ def chmod(self, val):+ """+ Change file/dir permissions::++ def build(bld):+ bld.path.chmod(493) # 0755+ """+ os.chmod(self.abspath(), val)++ def delete(self):+ """Delete the file/folders, and remove this node from the tree. It becomes invalid after that"""+ try:+ if getattr(self, 'children', None):+ shutil.rmtree(self.abspath())+ else:+ os.unlink(self.abspath())+ except OSError:+ pass+ self.evict()++ def evict(self):+ """Internal - called when a node is removed"""+ del self.parent.children[self.name]++ def suffix(self):+ """Return the file extension"""+ k = max(0, self.name.rfind('.'))+ return self.name[k:]++ def height(self):+ """Depth in the folder hierarchy from the filesystem root or from all the file drives"""+ d = self+ val = -1+ while d:+ d = d.parent+ val += 1+ return val++ def listdir(self):+ """List the folder contents"""+ lst = Utils.listdir(self.abspath())+ lst.sort()+ return lst++ def mkdir(self):+ """+ Create a folder represented by this node, creating intermediate nodes as needed+ An exception will be raised only when the folder cannot possibly exist there+ """+ if getattr(self, 'cache_isdir', None):+ return++ try:+ self.parent.mkdir()+ except OSError:+ pass++ if self.name:+ try:+ os.makedirs(self.abspath())+ except OSError:+ pass++ if not os.path.isdir(self.abspath()):+ raise Errors.WafError('Could not create the directory %s' % self.abspath())++ try:+ self.children+ except AttributeError:+ self.children = {}++ self.cache_isdir = True++ def find_node(self, lst):+ """+ Find a node on the file system (files or folders), create intermediate nodes as needed++ :param lst: path+ :type lst: string or list of string+ """++ if isinstance(lst, str):+ lst = [x for x in split_path(lst) if x and x != '.']++ cur = self+ for x in lst:+ if x == '..':+ cur = cur.parent or cur+ continue++ try:+ ch = cur.children+ except AttributeError:+ cur.children = {}+ else:+ try:+ cur = cur.children[x]+ continue+ except KeyError:+ pass++ # optimistic: create the node first then look if it was correct to do so+ cur = self.__class__(x, cur)+ try:+ os.stat(cur.abspath())+ except OSError:+ cur.evict()+ return None++ ret = cur++ try:+ os.stat(ret.abspath())+ except OSError:+ ret.evict()+ return None++ try:+ while not getattr(cur.parent, 'cache_isdir', None):+ cur = cur.parent+ cur.cache_isdir = True+ except AttributeError:+ pass++ return ret++ def make_node(self, lst):+ """+ Find or create a node without looking on the filesystem++ :param lst: path+ :type lst: string or list of string+ """+ if isinstance(lst, str):+ lst = [x for x in split_path(lst) if x and x != '.']++ cur = self+ for x in lst:+ if x == '..':+ cur = cur.parent or cur+ continue++ if getattr(cur, 'children', {}):+ if x in cur.children:+ cur = cur.children[x]+ continue+ else:+ cur.children = {}+ cur = self.__class__(x, cur)+ return cur++ def search_node(self, lst):+ """+ Search for a node without looking on the filesystem++ :param lst: path+ :type lst: string or list of string+ """+ if isinstance(lst, str):+ lst = [x for x in split_path(lst) if x and x != '.']++ cur = self+ for x in lst:+ if x == '..':+ cur = cur.parent or cur+ else:+ try:+ cur = cur.children[x]+ except (AttributeError, KeyError):+ return None+ return cur++ def path_from(self, node):+ """+ Path of this node seen from the other::++ def build(bld):+ n1 = bld.path.find_node('foo/bar/xyz.txt')+ n2 = bld.path.find_node('foo/stuff/')+ n1.path_from(n2) # './bar/xyz.txt'++ :param node: path to use as a reference+ :type node: :py:class:`waflib.Node.Node`+ """++ c1 = self+ c2 = node++ c1h = c1.height()+ c2h = c2.height()++ lst = []+ up = 0++ while c1h > c2h:+ lst.append(c1.name)+ c1 = c1.parent+ c1h -= 1++ while c2h > c1h:+ up += 1+ c2 = c2.parent+ c2h -= 1++ while id(c1) != id(c2):+ lst.append(c1.name)+ up += 1++ c1 = c1.parent+ c2 = c2.parent++ for i in range(up):+ lst.append('..')+ lst.reverse()+ return os.sep.join(lst) or '.'++ def abspath(self):+ """+ Absolute path. A cache is kept in the context as ``cache_node_abspath``+ """+ try:+ return self.cache_abspath+ except AttributeError:+ pass+ # think twice before touching this (performance + complexity + correctness)++ if os.sep == '/':+ if not self.parent:+ val = os.sep+ elif not self.parent.name:+ val = os.sep + self.name+ else:+ val = self.parent.abspath() + os.sep + self.name+ else:+ if not self.parent:+ val = ''+ elif not self.parent.name:+ val = self.name + os.sep+ else:+ val = self.parent.abspath().rstrip(os.sep) + os.sep + self.name++ self.cache_abspath = val+ return val++ def is_child_of(self, node):+ """+ Does this node belong to the subtree node?::++ def build(bld):+ node = bld.path.find_node('wscript')+ node.is_child_of(bld.path) # True++ :param node: path to use as a reference+ :type node: :py:class:`waflib.Node.Node`+ """+ p = self+ diff = self.height() - node.height()+ while diff > 0:+ diff -= 1+ p = p.parent+ return id(p) == id(node)++ def ant_iter(self, accept=None, maxdepth=25, pats=[], dir=False, src=True, remove=True):+ """+ Semi-private and recursive method used by ant_glob.++ :param accept: function used for accepting/rejecting a node, returns the patterns that can be still accepted in recursion+ :type accept: function+ :param maxdepth: maximum depth in the filesystem (25)+ :type maxdepth: int+ :param pats: list of patterns to accept and list of patterns to exclude+ :type pats: tuple+ :param dir: return folders too (False by default)+ :type dir: bool+ :param src: return files (True by default)+ :type src: bool+ :param remove: remove files/folders that do not exist (True by default)+ :type remove: bool+ """+ dircont = self.listdir()+ dircont.sort()++ try:+ lst = set(self.children.keys())+ except AttributeError:+ self.children = {}+ else:+ if remove:+ for x in lst - set(dircont):+ self.children[x].evict()++ for name in dircont:+ npats = accept(name, pats)+ if npats and npats[0]:+ accepted = [] in npats[0]++ node = self.make_node([name])++ isdir = os.path.isdir(node.abspath())+ if accepted:+ if isdir:+ if dir:+ yield node+ else:+ if src:+ yield node++ if getattr(node, 'cache_isdir', None) or isdir:+ node.cache_isdir = True+ if maxdepth:+ for k in node.ant_iter(accept=accept, maxdepth=maxdepth - 1, pats=npats, dir=dir, src=src, remove=remove):+ yield k+ raise StopIteration++ def ant_glob(self, *k, **kw):+ """+ This method is used for finding files across folders. It behaves like ant patterns:++ * ``**/*`` find all files recursively+ * ``**/*.class`` find all files ending by .class+ * ``..`` find files having two dot characters++ For example::++ def configure(cfg):+ cfg.path.ant_glob('**/*.cpp') # find all .cpp files+ cfg.root.ant_glob('etc/*.txt') # using the filesystem root can be slow+ cfg.path.ant_glob('*.cpp', excl=['*.c'], src=True, dir=False)++ For more information see http://ant.apache.org/manual/dirtasks.html++ The nodes that correspond to files and folders that do not exist will be removed. To prevent this+ behaviour, pass 'remove=False'++ :param incl: ant patterns or list of patterns to include+ :type incl: string or list of strings+ :param excl: ant patterns or list of patterns to exclude+ :type excl: string or list of strings+ :param dir: return folders too (False by default)+ :type dir: bool+ :param src: return files (True by default)+ :type src: bool+ :param remove: remove files/folders that do not exist (True by default)+ :type remove: bool+ :param maxdepth: maximum depth of recursion+ :type maxdepth: int+ :param ignorecase: ignore case while matching (False by default)+ :type ignorecase: bool+ """++ src = kw.get('src', True)+ dir = kw.get('dir', False)++ excl = kw.get('excl', exclude_regs)+ incl = k and k[0] or kw.get('incl', '**')+ reflags = kw.get('ignorecase', 0) and re.I++ def to_pat(s):+ lst = Utils.to_list(s)+ ret = []+ for x in lst:+ x = x.replace('\\', '/').replace('//', '/')+ if x.endswith('/'):+ x += '**'+ lst2 = x.split('/')+ accu = []+ for k in lst2:+ if k == '**':+ accu.append(k)+ else:+ k = k.replace('.', '[.]').replace('*','.*').replace('?', '.').replace('+', '\\+')+ k = '^%s$' % k+ try:+ #print "pattern", k+ accu.append(re.compile(k, flags=reflags))+ except Exception as e:+ raise Errors.WafError("Invalid pattern: %s" % k, e)+ ret.append(accu)+ return ret++ def filtre(name, nn):+ ret = []+ for lst in nn:+ if not lst:+ pass+ elif lst[0] == '**':+ ret.append(lst)+ if len(lst) > 1:+ if lst[1].match(name):+ ret.append(lst[2:])+ else:+ ret.append([])+ elif lst[0].match(name):+ ret.append(lst[1:])+ return ret++ def accept(name, pats):+ nacc = filtre(name, pats[0])+ nrej = filtre(name, pats[1])+ if [] in nrej:+ nacc = []+ return [nacc, nrej]++ ret = [x for x in self.ant_iter(accept=accept, pats=[to_pat(incl), to_pat(excl)], maxdepth=25, dir=dir, src=src, remove=kw.get('remove', True))]+ if kw.get('flat', False):+ return ' '.join([x.path_from(self) for x in ret])++ return ret++ # --------------------------------------------------------------------------------+ # the following methods require the source/build folders (bld.srcnode/bld.bldnode)+ # using a subclass is a possibility, but is that really necessary?+ # --------------------------------------------------------------------------------++ def is_src(self):+ """+ True if the node is below the source directory+ note: !is_src does not imply is_bld()++ :rtype: bool+ """+ cur = self+ x = id(self.ctx.srcnode)+ y = id(self.ctx.bldnode)+ while cur.parent:+ if id(cur) == y:+ return False+ if id(cur) == x:+ return True+ cur = cur.parent+ return False++ def is_bld(self):+ """+ True if the node is below the build directory+ note: !is_bld does not imply is_src++ :rtype: bool+ """+ cur = self+ y = id(self.ctx.bldnode)+ while cur.parent:+ if id(cur) == y:+ return True+ cur = cur.parent+ return False++ def get_src(self):+ """+ Return the equivalent src node (or self if not possible)++ :rtype: :py:class:`waflib.Node.Node`+ """+ cur = self+ x = id(self.ctx.srcnode)+ y = id(self.ctx.bldnode)+ lst = []+ while cur.parent:+ if id(cur) == y:+ lst.reverse()+ return self.ctx.srcnode.make_node(lst)+ if id(cur) == x:+ return self+ lst.append(cur.name)+ cur = cur.parent+ return self++ def get_bld(self):+ """+ Return the equivalent bld node (or self if not possible)++ :rtype: :py:class:`waflib.Node.Node`+ """+ cur = self+ x = id(self.ctx.srcnode)+ y = id(self.ctx.bldnode)+ lst = []+ while cur.parent:+ if id(cur) == y:+ return self+ if id(cur) == x:+ lst.reverse()+ return self.ctx.bldnode.make_node(lst)+ lst.append(cur.name)+ cur = cur.parent+ # the file is external to the current project, make a fake root in the current build directory+ lst.reverse()+ if lst and Utils.is_win32 and len(lst[0]) == 2 and lst[0].endswith(':'):+ lst[0] = lst[0][0]+ return self.ctx.bldnode.make_node(['__root__'] + lst)++ def find_resource(self, lst):+ """+ Try to find a declared build node or a source file++ :param lst: path+ :type lst: string or list of string+ """+ if isinstance(lst, str):+ lst = [x for x in split_path(lst) if x and x != '.']++ node = self.get_bld().search_node(lst)+ if not node:+ self = self.get_src()+ node = self.find_node(lst)+ if node:+ if os.path.isdir(node.abspath()):+ return None+ return node++ def find_or_declare(self, lst):+ """+ if 'self' is in build directory, try to return an existing node+ if no node is found, go to the source directory+ try to find an existing node in the source directory+ if no node is found, create it in the build directory++ :param lst: path+ :type lst: string or list of string+ """+ if isinstance(lst, str):+ lst = [x for x in split_path(lst) if x and x != '.']++ node = self.get_bld().search_node(lst)+ if node:+ if not os.path.isfile(node.abspath()):+ node.sig = None+ node.parent.mkdir()+ return node+ self = self.get_src()+ node = self.find_node(lst)+ if node:+ if not os.path.isfile(node.abspath()):+ node.sig = None+ node.parent.mkdir()+ return node+ node = self.get_bld().make_node(lst)+ node.parent.mkdir()+ return node++ def find_dir(self, lst):+ """+ Search for a folder in the filesystem++ :param lst: path+ :type lst: string or list of string+ """+ if isinstance(lst, str):+ lst = [x for x in split_path(lst) if x and x != '.']++ node = self.find_node(lst)+ try:+ if not os.path.isdir(node.abspath()):+ return None+ except (OSError, AttributeError):+ # the node might be None, and raise an AttributeError+ return None+ return node++ # helpers for building things+ def change_ext(self, ext, ext_in=None):+ """+ :return: A build node of the same path, but with a different extension+ :rtype: :py:class:`waflib.Node.Node`+ """+ name = self.name+ if ext_in is None:+ k = name.rfind('.')+ if k >= 0:+ name = name[:k] + ext+ else:+ name = name + ext+ else:+ name = name[:- len(ext_in)] + ext++ return self.parent.find_or_declare([name])++ def nice_path(self, env=None):+ """+ Return the path seen from the launch directory.+ Can be used for opening files easily (copy-paste in the console).+ """+ return self.path_from(self.ctx.launch_node())++ def bldpath(self):+ "Path seen from the build directory default/src/foo.cpp"+ return self.path_from(self.ctx.bldnode)++ def srcpath(self):+ "Path seen from the source directory ../src/foo.cpp"+ return self.path_from(self.ctx.srcnode)++ def relpath(self):+ "If a file in the build directory, bldpath, else srcpath"+ cur = self+ x = id(self.ctx.bldnode)+ while cur.parent:+ if id(cur) == x:+ return self.bldpath()+ cur = cur.parent+ return self.srcpath()++ def bld_dir(self):+ "Build path without the file name"+ return self.parent.bldpath()++ def bld_base(self):+ "Build path without the extension: src/dir/foo(.cpp)"+ s = os.path.splitext(self.name)[0]+ return self.bld_dir() + os.sep + s++ def get_bld_sig(self):+ """+ Node signature, assuming the file is in the build directory+ """+ try:+ return self.cache_sig+ except AttributeError:+ pass++ if not self.is_bld() or self.ctx.bldnode is self.ctx.srcnode:+ self.sig = Utils.h_file(self.abspath())+ self.cache_sig = ret = self.sig+ return ret+++ # TODO Waf 1.8+ search = search_node++pickle_lock = Utils.threading.Lock()+"""Lock mandatory for thread-safe node serialization"""++class Nod3(Node):+ """Mandatory subclass for thread-safe node serialization"""+ pass # do not remove++new file mode 100644@@ -0,0 +1,254 @@+#!/usr/bin/env python+# encoding: utf-8+# Scott Newton, 2005 (scottn)+# Thomas Nagy, 2006-2010 (ita)++"""+Support for waf command-line options++Provides default command-line options,+as well as custom ones, used by the ``options`` wscript function.++"""++import os, tempfile, optparse, sys, re+from waflib import Logs, Utils, Context++cmds = 'distclean configure build install clean uninstall check dist distcheck'.split()+"""+Constant representing the default waf commands displayed in::++ $ waf --help++"""++options = {}+"""+A dictionary representing the command-line options::++ $ waf --foo=bar++"""++commands = []+"""+List of commands to execute extracted from the command-line. This list is consumed during the execution, see :py:func:`waflib.Scripting.run_commands`.+"""++lockfile = os.environ.get('WAFLOCK', '.lock-waf_%s_build' % sys.platform)+try: cache_global = os.path.abspath(os.environ['WAFCACHE'])+except KeyError: cache_global = ''+platform = Utils.unversioned_sys_platform()+++class opt_parser(optparse.OptionParser):+ """+ Command-line options parser.+ """+ def __init__(self, ctx):+ optparse.OptionParser.__init__(self, conflict_handler="resolve", version='waf %s (%s)' % (Context.WAFVERSION, Context.WAFREVISION))++ self.formatter.width = Logs.get_term_cols()+ p = self.add_option+ self.ctx = ctx++ jobs = ctx.jobs()+ p('-j', '--jobs', dest='jobs', default=jobs, type='int', help='amount of parallel jobs (%r)' % jobs)+ p('-k', '--keep', dest='keep', default=0, action='count', help='keep running happily even if errors are found')+ p('-v', '--verbose', dest='verbose', default=0, action='count', help='verbosity level -v -vv or -vvv [default: 0]')+ p('--nocache', dest='nocache', default=False, action='store_true', help='ignore the WAFCACHE (if set)')+ p('--zones', dest='zones', default='', action='store', help='debugging zones (task_gen, deps, tasks, etc)')++ gr = optparse.OptionGroup(self, 'configure options')+ self.add_option_group(gr)++ gr.add_option('-o', '--out', action='store', default='', help='build dir for the project', dest='out')+ gr.add_option('-t', '--top', action='store', default='', help='src dir for the project', dest='top')++ default_prefix = os.environ.get('PREFIX')+ if not default_prefix:+ if platform == 'win32':+ d = tempfile.gettempdir()+ default_prefix = d[0].upper() + d[1:]+ # win32 preserves the case, but gettempdir does not+ else:+ default_prefix = '/usr/local/'+ gr.add_option('--prefix', dest='prefix', default=default_prefix, help='installation prefix [default: %r]' % default_prefix)+ gr.add_option('--download', dest='download', default=False, action='store_true', help='try to download the tools if missing')+++ gr = optparse.OptionGroup(self, 'build and install options')+ self.add_option_group(gr)++ gr.add_option('-p', '--progress', dest='progress_bar', default=0, action='count', help= '-p: progress bar; -pp: ide output')+ gr.add_option('--targets', dest='targets', default='', action='store', help='task generators, e.g. "target1,target2"')++ gr = optparse.OptionGroup(self, 'step options')+ self.add_option_group(gr)+ gr.add_option('--files', dest='files', default='', action='store', help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"')++ default_destdir = os.environ.get('DESTDIR', '')+ gr = optparse.OptionGroup(self, 'install/uninstall options')+ self.add_option_group(gr)+ gr.add_option('--destdir', help='installation root [default: %r]' % default_destdir, default=default_destdir, dest='destdir')+ gr.add_option('-f', '--force', dest='force', default=False, action='store_true', help='force file installation')++ gr.add_option('--distcheck-args', help='arguments to pass to distcheck', default=None, action='store')++ def get_usage(self):+ """+ Return the message to print on ``waf --help``+ """+ cmds_str = {}+ for cls in Context.classes:+ if not cls.cmd or cls.cmd == 'options':+ continue++ s = cls.__doc__ or ''+ cmds_str[cls.cmd] = s++ if Context.g_module:+ for (k, v) in Context.g_module.__dict__.items():+ if k in ['options', 'init', 'shutdown']:+ continue++ if type(v) is type(Context.create_context):+ if v.__doc__ and not k.startswith('_'):+ cmds_str[k] = v.__doc__++ just = 0+ for k in cmds_str:+ just = max(just, len(k))++ lst = [' %s: %s' % (k.ljust(just), v) for (k, v) in cmds_str.items()]+ lst.sort()+ ret = '\n'.join(lst)++ return '''waf [commands] [options]++Main commands (example: ./waf build -j4)+%s+''' % ret+++class OptionsContext(Context.Context):+ """+ Collect custom options from wscript files and parses the command line.+ Set the global :py:const:`waflib.Options.commands` and :py:const:`waflib.Options.options` values.+ """++ cmd = 'options'+ fun = 'options'++ def __init__(self, **kw):+ super(OptionsContext, self).__init__(**kw)++ self.parser = opt_parser(self)+ """Instance of :py:class:`waflib.Options.opt_parser`"""++ self.option_groups = {}++ def jobs(self):+ """+ Find the amount of cpu cores to set the default amount of tasks executed in parallel. At+ runtime the options can be obtained from :py:const:`waflib.Options.options` ::++ from waflib.Options import options+ njobs = options.jobs++ :return: the amount of cpu cores+ :rtype: int+ """+ count = int(os.environ.get('JOBS', 0))+ if count < 1:+ if 'NUMBER_OF_PROCESSORS' in os.environ:+ # on Windows, use the NUMBER_OF_PROCESSORS environment variable+ count = int(os.environ.get('NUMBER_OF_PROCESSORS', 1))+ else:+ # on everything else, first try the POSIX sysconf values+ if hasattr(os, 'sysconf_names'):+ if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:+ count = int(os.sysconf('SC_NPROCESSORS_ONLN'))+ elif 'SC_NPROCESSORS_CONF' in os.sysconf_names:+ count = int(os.sysconf('SC_NPROCESSORS_CONF'))+ if not count and os.name not in ('nt', 'java'):+ try:+ tmp = self.cmd_and_log(['sysctl', '-n', 'hw.ncpu'], quiet=0)+ except Exception:+ pass+ else:+ if re.match('^[0-9]+$', tmp):+ count = int(tmp)+ if count < 1:+ count = 1+ elif count > 1024:+ count = 1024+ return count++ def add_option(self, *k, **kw):+ """+ Wrapper for optparse.add_option::++ def options(ctx):+ ctx.add_option('-u', '--use', dest='use', default=False, action='store_true',+ help='a boolean option')+ """+ return self.parser.add_option(*k, **kw)++ def add_option_group(self, *k, **kw):+ """+ Wrapper for optparse.add_option_group::++ def options(ctx):+ gr = ctx.add_option_group('some options')+ gr.add_option('-u', '--use', dest='use', default=False, action='store_true')+ """+ try:+ gr = self.option_groups[k[0]]+ except KeyError:+ gr = self.parser.add_option_group(*k, **kw)+ self.option_groups[k[0]] = gr+ return gr++ def get_option_group(self, opt_str):+ """+ Wrapper for optparse.get_option_group::++ def options(ctx):+ gr = ctx.get_option_group('configure options')+ gr.add_option('-o', '--out', action='store', default='',+ help='build dir for the project', dest='out')++ """+ try:+ return self.option_groups[opt_str]+ except KeyError:+ for group in self.parser.option_groups:+ if group.title == opt_str:+ return group+ return None++ def parse_args(self, _args=None):+ """+ Parse arguments from a list (not bound to the command-line).++ :param _args: arguments+ :type _args: list of strings+ """+ global options, commands+ (options, leftover_args) = self.parser.parse_args(args=_args)+ commands = leftover_args++ if options.destdir:+ options.destdir = os.path.abspath(os.path.expanduser(options.destdir))++ if options.verbose >= 1:+ self.load('errcheck')++ def execute(self):+ """+ See :py:func:`waflib.Context.Context.execute`+ """+ super(OptionsContext, self).execute()+ self.parse_args()+new file mode 100644@@ -0,0 +1,361 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""+Runner.py: Task scheduling and execution++"""++import random, atexit+try:+ from queue import Queue+except ImportError:+ from Queue import Queue+from waflib import Utils, Task, Errors, Logs++GAP = 10+"""+Wait for free tasks if there are at least ``GAP * njobs`` in queue+"""++class TaskConsumer(Utils.threading.Thread):+ """+ Task consumers belong to a pool of workers++ They wait for tasks in the queue and then use ``task.process(...)``+ """+ def __init__(self):+ Utils.threading.Thread.__init__(self)+ self.ready = Queue()+ """+ Obtain :py:class:`waflib.Task.TaskBase` instances from this queue.+ """+ self.setDaemon(1)+ self.start()++ def run(self):+ """+ Loop over the tasks to execute+ """+ try:+ self.loop()+ except Exception:+ pass++ def loop(self):+ """+ Obtain tasks from :py:attr:`waflib.Runner.TaskConsumer.ready` and call+ :py:meth:`waflib.Task.TaskBase.process`. If the object is a function, execute it.+ """+ while 1:+ tsk = self.ready.get()+ if not isinstance(tsk, Task.TaskBase):+ tsk(self)+ else:+ tsk.process()++pool = Queue()+"""+Pool of task consumer objects+"""++def get_pool():+ """+ Obtain a task consumer from :py:attr:`waflib.Runner.pool`.+ Do not forget to put it back by using :py:func:`waflib.Runner.put_pool`+ and reset properly (original waiting queue).++ :rtype: :py:class:`waflib.Runner.TaskConsumer`+ """+ try:+ return pool.get(False)+ except Exception:+ return TaskConsumer()++def put_pool(x):+ """+ Return a task consumer to the thread pool :py:attr:`waflib.Runner.pool`++ :param x: task consumer object+ :type x: :py:class:`waflib.Runner.TaskConsumer`+ """+ pool.put(x)++def _free_resources():+ global pool+ lst = []+ while pool.qsize():+ lst.append(pool.get())+ for x in lst:+ x.ready.put(None)+ for x in lst:+ x.join()+ pool = None+atexit.register(_free_resources)++class Parallel(object):+ """+ Schedule the tasks obtained from the build context for execution.+ """+ def __init__(self, bld, j=2):+ """+ The initialization requires a build context reference+ for computing the total number of jobs.+ """++ self.numjobs = j+ """+ Number of consumers in the pool+ """++ self.bld = bld+ """+ Instance of :py:class:`waflib.Build.BuildContext`+ """++ self.outstanding = []+ """List of :py:class:`waflib.Task.TaskBase` that may be ready to be executed"""++ self.frozen = []+ """List of :py:class:`waflib.Task.TaskBase` that cannot be executed immediately"""++ self.out = Queue(0)+ """List of :py:class:`waflib.Task.TaskBase` returned by the task consumers"""++ self.count = 0+ """Amount of tasks that may be processed by :py:class:`waflib.Runner.TaskConsumer`"""++ self.processed = 1+ """Amount of tasks processed"""++ self.stop = False+ """Error flag to stop the build"""++ self.error = []+ """Tasks that could not be executed"""++ self.biter = None+ """Task iterator which must give groups of parallelizable tasks when calling ``next()``"""++ self.dirty = False+ """Flag to indicate that tasks have been executed, and that the build cache must be saved (call :py:meth:`waflib.Build.BuildContext.store`)"""++ def get_next_task(self):+ """+ Obtain the next task to execute.++ :rtype: :py:class:`waflib.Task.TaskBase`+ """+ if not self.outstanding:+ return None+ return self.outstanding.pop(0)++ def postpone(self, tsk):+ """+ A task cannot be executed at this point, put it in the list :py:attr:`waflib.Runner.Parallel.frozen`.++ :param tsk: task+ :type tsk: :py:class:`waflib.Task.TaskBase`+ """+ if random.randint(0, 1):+ self.frozen.insert(0, tsk)+ else:+ self.frozen.append(tsk)++ def refill_task_list(self):+ """+ Put the next group of tasks to execute in :py:attr:`waflib.Runner.Parallel.outstanding`.+ """+ while self.count > self.numjobs * GAP:+ self.get_out()++ while not self.outstanding:+ if self.count:+ self.get_out()+ elif self.frozen:+ try:+ cond = self.deadlock == self.processed+ except AttributeError:+ pass+ else:+ if cond:+ msg = 'check the build order for the tasks'+ for tsk in self.frozen:+ if not tsk.run_after:+ msg = 'check the methods runnable_status'+ break+ lst = []+ for tsk in self.frozen:+ lst.append('%s\t-> %r' % (repr(tsk), [id(x) for x in tsk.run_after]))+ raise Errors.WafError('Deadlock detected: %s%s' % (msg, ''.join(lst)))+ self.deadlock = self.processed++ if self.frozen:+ self.outstanding += self.frozen+ self.frozen = []+ elif not self.count:+ self.outstanding.extend(next(self.biter))+ self.total = self.bld.total()+ break++ def add_more_tasks(self, tsk):+ """+ Tasks may be added dynamically during the build by binding them to the task :py:attr:`waflib.Task.TaskBase.more_tasks`++ :param tsk: task+ :type tsk: :py:attr:`waflib.Task.TaskBase`+ """+ if getattr(tsk, 'more_tasks', None):+ self.outstanding += tsk.more_tasks+ self.total += len(tsk.more_tasks)++ def get_out(self):+ """+ Obtain one task returned from the task consumers, and update the task count. Add more tasks if necessary through+ :py:attr:`waflib.Runner.Parallel.add_more_tasks`.++ :rtype: :py:attr:`waflib.Task.TaskBase`+ """+ tsk = self.out.get()+ if not self.stop:+ self.add_more_tasks(tsk)+ self.count -= 1+ self.dirty = True+ return tsk++ def error_handler(self, tsk):+ """+ Called when a task cannot be executed. The flag :py:attr:`waflib.Runner.Parallel.stop` is set, unless+ the build is executed with::++ $ waf build -k++ :param tsk: task+ :type tsk: :py:attr:`waflib.Task.TaskBase`+ """+ if not self.bld.keep:+ self.stop = True+ self.error.append(tsk)++ def add_task(self, tsk):+ """+ Pass a task to a consumer.++ :param tsk: task+ :type tsk: :py:attr:`waflib.Task.TaskBase`+ """+ try:+ self.pool+ except AttributeError:+ self.init_task_pool()+ self.ready.put(tsk)++ def init_task_pool(self):+ # lazy creation, and set a common pool for all task consumers+ pool = self.pool = [get_pool() for i in range(self.numjobs)]+ self.ready = Queue(0)+ def setq(consumer):+ consumer.ready = self.ready+ for x in pool:+ x.ready.put(setq)+ return pool++ def free_task_pool(self):+ # return the consumers, setting a different queue for each of them+ def setq(consumer):+ consumer.ready = Queue(0)+ self.out.put(self)+ try:+ pool = self.pool+ except AttributeError:+ pass+ else:+ for x in pool:+ self.ready.put(setq)+ for x in pool:+ self.get_out()+ for x in pool:+ put_pool(x)+ self.pool = []++ def start(self):+ """+ Give tasks to :py:class:`waflib.Runner.TaskConsumer` instances until the build finishes or the ``stop`` flag is set.+ If only one job is used, then execute the tasks one by one, without consumers.+ """++ self.total = self.bld.total()++ while not self.stop:++ self.refill_task_list()++ # consider the next task+ tsk = self.get_next_task()+ if not tsk:+ if self.count:+ # tasks may add new ones after they are run+ continue+ else:+ # no tasks to run, no tasks running, time to exit+ break++ if tsk.hasrun:+ # if the task is marked as "run", just skip it+ self.processed += 1+ continue++ if self.stop: # stop immediately after a failure was detected+ break++ try:+ st = tsk.runnable_status()+ except Exception:+ self.processed += 1+ # TODO waf 1.7 this piece of code should go in the error_handler+ tsk.err_msg = Utils.ex_stack()+ if not self.stop and self.bld.keep:+ tsk.hasrun = Task.SKIPPED+ if self.bld.keep == 1:+ # if -k stop at the first exception, if -kk try to go as far as possible+ if Logs.verbose > 1 or not self.error:+ self.error.append(tsk)+ self.stop = True+ else:+ if Logs.verbose > 1:+ self.error.append(tsk)+ continue+ tsk.hasrun = Task.EXCEPTION+ self.error_handler(tsk)+ continue++ if st == Task.ASK_LATER:+ self.postpone(tsk)+ elif st == Task.SKIP_ME:+ self.processed += 1+ tsk.hasrun = Task.SKIPPED+ self.add_more_tasks(tsk)+ else:+ # run me: put the task in ready queue+ tsk.position = (self.processed, self.total)+ self.count += 1+ tsk.master = self+ self.processed += 1++ if self.numjobs == 1:+ tsk.process()+ else:+ self.add_task(tsk)++ # self.count represents the tasks that have been made available to the consumer threads+ # collect all the tasks after an error else the message may be incomplete+ while self.error and self.count:+ self.get_out()++ #print loop+ assert (self.count == 0 or self.stop)++ # free the task pool, if any+ self.free_task_pool()+new file mode 100644@@ -0,0 +1,579 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"Module called for configuring, compiling and installing targets"++import os, shlex, shutil, traceback, errno, sys, stat+from waflib import Utils, Configure, Logs, Options, ConfigSet, Context, Errors, Build, Node++build_dir_override = None++no_climb_commands = ['configure']++default_cmd = "build"++def waf_entry_point(current_directory, version, wafdir):+ """+ This is the main entry point, all Waf execution starts here.++ :param current_directory: absolute path representing the current directory+ :type current_directory: string+ :param version: version number+ :type version: string+ :param wafdir: absolute path representing the directory of the waf library+ :type wafdir: string+ """++ Logs.init_log()++ if Context.WAFVERSION != version:+ Logs.error('Waf script %r and library %r do not match (directory %r)' % (version, Context.WAFVERSION, wafdir))+ sys.exit(1)++ if '--version' in sys.argv:+ Context.run_dir = current_directory+ ctx = Context.create_context('options')+ ctx.curdir = current_directory+ ctx.parse_args()+ sys.exit(0)++ Context.waf_dir = wafdir+ Context.launch_dir = current_directory++ # if 'configure' is in the commands, do not search any further+ no_climb = os.environ.get('NOCLIMB', None)+ if not no_climb:+ for k in no_climb_commands:+ if k in sys.argv:+ no_climb = True+ break++ # try to find a lock file (if the project was configured)+ # at the same time, store the first wscript file seen+ cur = current_directory+ while cur:+ lst = os.listdir(cur)+ if Options.lockfile in lst:+ env = ConfigSet.ConfigSet()+ try:+ env.load(os.path.join(cur, Options.lockfile))+ ino = os.stat(cur)[stat.ST_INO]+ except Exception:+ pass+ else:+ # check if the folder was not moved+ for x in [env.run_dir, env.top_dir, env.out_dir]:+ if Utils.is_win32:+ if cur == x:+ load = True+ break+ else:+ # if the filesystem features symlinks, compare the inode numbers+ try:+ ino2 = os.stat(x)[stat.ST_INO]+ except OSError:+ pass+ else:+ if ino == ino2:+ load = True+ break+ else:+ Logs.warn('invalid lock file in %s' % cur)+ load = False++ if load:+ Context.run_dir = env.run_dir+ Context.top_dir = env.top_dir+ Context.out_dir = env.out_dir+ break++ if not Context.run_dir:+ if Context.WSCRIPT_FILE in lst:+ Context.run_dir = cur++ next = os.path.dirname(cur)+ if next == cur:+ break+ cur = next++ if no_climb:+ break++ if not Context.run_dir:+ if '-h' in sys.argv or '--help' in sys.argv:+ Logs.warn('No wscript file found: the help message may be incomplete')+ Context.run_dir = current_directory+ ctx = Context.create_context('options')+ ctx.curdir = current_directory+ ctx.parse_args()+ sys.exit(0)+ Logs.error('Waf: Run from a directory containing a file named %r' % Context.WSCRIPT_FILE)+ sys.exit(1)++ try:+ os.chdir(Context.run_dir)+ except OSError:+ Logs.error('Waf: The folder %r is unreadable' % Context.run_dir)+ sys.exit(1)++ try:+ set_main_module(Context.run_dir + os.sep + Context.WSCRIPT_FILE)+ except Errors.WafError as e:+ Logs.pprint('RED', e.verbose_msg)+ Logs.error(str(e))+ sys.exit(1)+ except Exception as e:+ Logs.error('Waf: The wscript in %r is unreadable' % Context.run_dir, e)+ traceback.print_exc(file=sys.stdout)+ sys.exit(2)++ """+ import cProfile, pstats+ cProfile.runctx("from waflib import Scripting; Scripting.run_commands()", {}, {}, 'profi.txt')+ p = pstats.Stats('profi.txt')+ p.sort_stats('time').print_stats(25) # or 'cumulative'+ """+ try:+ run_commands()+ except Errors.WafError as e:+ if Logs.verbose > 1:+ Logs.pprint('RED', e.verbose_msg)+ Logs.error(e.msg)+ sys.exit(1)+ except SystemExit:+ raise+ except Exception as e:+ traceback.print_exc(file=sys.stdout)+ sys.exit(2)+ except KeyboardInterrupt:+ Logs.pprint('RED', 'Interrupted')+ sys.exit(68)+ #"""++def set_main_module(file_path):+ """+ Read the main wscript file into :py:const:`waflib.Context.Context.g_module` and+ bind default functions such as ``init``, ``dist``, ``distclean`` if not defined.+ Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization.++ :param file_path: absolute path representing the top-level wscript file+ :type file_path: string+ """+ Context.g_module = Context.load_module(file_path)+ Context.g_module.root_path = file_path++ # note: to register the module globally, use the following:+ # sys.modules['wscript_main'] = g_module++ def set_def(obj):+ name = obj.__name__+ if not name in Context.g_module.__dict__:+ setattr(Context.g_module, name, obj)+ for k in [update, dist, distclean, distcheck, update]:+ set_def(k)+ # add dummy init and shutdown functions if they're not defined+ if not 'init' in Context.g_module.__dict__:+ Context.g_module.init = Utils.nada+ if not 'shutdown' in Context.g_module.__dict__:+ Context.g_module.shutdown = Utils.nada+ if not 'options' in Context.g_module.__dict__:+ Context.g_module.options = Utils.nada++def parse_options():+ """+ Parse the command-line options and initialize the logging system.+ Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization.+ """+ Context.create_context('options').execute()++ if not Options.commands:+ Options.commands = [default_cmd]+ Options.commands = [x for x in Options.commands if x != 'options'] # issue 1076++ # process some internal Waf options+ Logs.verbose = Options.options.verbose+ Logs.init_log()++ if Options.options.zones:+ Logs.zones = Options.options.zones.split(',')+ if not Logs.verbose:+ Logs.verbose = 1+ elif Logs.verbose > 0:+ Logs.zones = ['runner']++ if Logs.verbose > 2:+ Logs.zones = ['*']++def run_command(cmd_name):+ """+ Execute a single command. Called by :py:func:`waflib.Scripting.run_commands`.++ :param cmd_name: command to execute, like ``build``+ :type cmd_name: string+ """+ ctx = Context.create_context(cmd_name)+ ctx.log_timer = Utils.Timer()+ ctx.options = Options.options # provided for convenience+ ctx.cmd = cmd_name+ ctx.execute()+ return ctx++def run_commands():+ """+ Execute the commands that were given on the command-line, and the other options+ Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization, and executed+ after :py:func:`waflib.Scripting.parse_options`.+ """+ parse_options()+ run_command('init')+ while Options.commands:+ cmd_name = Options.commands.pop(0)+ ctx = run_command(cmd_name)+ Logs.info('%r finished successfully (%s)' % (cmd_name, str(ctx.log_timer)))+ run_command('shutdown')++###########################################################################################++def _can_distclean(name):+ # WARNING: this method may disappear anytime+ for k in '.o .moc .exe'.split():+ if name.endswith(k):+ return True+ return False++def distclean_dir(dirname):+ """+ Distclean function called in the particular case when::++ top == out++ :param dirname: absolute path of the folder to clean+ :type dirname: string+ """+ for (root, dirs, files) in os.walk(dirname):+ for f in files:+ if _can_distclean(f):+ fname = root + os.sep + f+ try:+ os.unlink(fname)+ except OSError:+ Logs.warn('Could not remove %r' % fname)++ for x in [Context.DBFILE, 'config.log']:+ try:+ os.unlink(x)+ except OSError:+ pass++ try:+ shutil.rmtree('c4che')+ except OSError:+ pass++def distclean(ctx):+ '''removes the build directory'''+ lst = os.listdir('.')+ for f in lst:+ if f == Options.lockfile:+ try:+ proj = ConfigSet.ConfigSet(f)+ except IOError:+ Logs.warn('Could not read %r' % f)+ continue++ if proj['out_dir'] != proj['top_dir']:+ try:+ shutil.rmtree(proj['out_dir'])+ except IOError:+ pass+ except OSError as e:+ if e.errno != errno.ENOENT:+ Logs.warn('project %r cannot be removed' % proj[Context.OUT])+ else:+ distclean_dir(proj['out_dir'])++ for k in (proj['out_dir'], proj['top_dir'], proj['run_dir']):+ try:+ os.remove(os.path.join(k, Options.lockfile))+ except OSError as e:+ if e.errno != errno.ENOENT:+ Logs.warn('file %r cannot be removed' % f)++ # remove the local waf cache+ if f.startswith('.waf') and not Options.commands:+ shutil.rmtree(f, ignore_errors=True)++class Dist(Context.Context):+ '''creates an archive containing the project source code'''+ cmd = 'dist'+ fun = 'dist'+ algo = 'tar.bz2'+ ext_algo = {}++ def execute(self):+ """+ See :py:func:`waflib.Context.Context.execute`+ """+ self.recurse([os.path.dirname(Context.g_module.root_path)])+ self.archive()++ def archive(self):+ """+ Create the archive.+ """+ import tarfile++ arch_name = self.get_arch_name()++ try:+ self.base_path+ except AttributeError:+ self.base_path = self.path++ node = self.base_path.make_node(arch_name)+ try:+ node.delete()+ except Exception:+ pass++ files = self.get_files()++ if self.algo.startswith('tar.'):+ tar = tarfile.open(arch_name, 'w:' + self.algo.replace('tar.', ''))++ for x in files:+ self.add_tar_file(x, tar)+ tar.close()+ elif self.algo == 'zip':+ import zipfile+ zip = zipfile.ZipFile(arch_name, 'w', compression=zipfile.ZIP_DEFLATED)++ for x in files:+ archive_name = self.get_base_name() + '/' + x.path_from(self.base_path)+ zip.write(x.abspath(), archive_name, zipfile.ZIP_DEFLATED)+ zip.close()+ else:+ self.fatal('Valid algo types are tar.bz2, tar.gz or zip')++ try:+ from hashlib import sha1 as sha+ except ImportError:+ from sha import sha+ try:+ digest = " (sha=%r)" % sha(node.read()).hexdigest()+ except Exception:+ digest = ''++ Logs.info('New archive created: %s%s' % (self.arch_name, digest))++ def get_tar_path(self, node):+ """+ return the path to use for a node in the tar archive, the purpose of this+ is to let subclases resolve symbolic links or to change file names+ """+ return node.abspath()++ def add_tar_file(self, x, tar):+ """+ Add a file to the tar archive. Transform symlinks into files if the files lie out of the project tree.+ """+ p = self.get_tar_path(x)+ tinfo = tar.gettarinfo(name=p, arcname=self.get_tar_prefix() + '/' + x.path_from(self.base_path))+ tinfo.uid = 0+ tinfo.gid = 0+ tinfo.uname = 'root'+ tinfo.gname = 'root'++ fu = None+ try:+ fu = open(p, 'rb')+ tar.addfile(tinfo, fileobj=fu)+ finally:+ if fu:+ fu.close()++ def get_tar_prefix(self):+ try:+ return self.tar_prefix+ except AttributeError:+ return self.get_base_name()++ def get_arch_name(self):+ """+ Return the name of the archive to create. Change the default value by setting *arch_name*::++ def dist(ctx):+ ctx.arch_name = 'ctx.tar.bz2'++ :rtype: string+ """+ try:+ self.arch_name+ except AttributeError:+ self.arch_name = self.get_base_name() + '.' + self.ext_algo.get(self.algo, self.algo)+ return self.arch_name++ def get_base_name(self):+ """+ Return the default name of the main directory in the archive, which is set to *appname-version*.+ Set the attribute *base_name* to change the default value::++ def dist(ctx):+ ctx.base_name = 'files'++ :rtype: string+ """+ try:+ self.base_name+ except AttributeError:+ appname = getattr(Context.g_module, Context.APPNAME, 'noname')+ version = getattr(Context.g_module, Context.VERSION, '1.0')+ self.base_name = appname + '-' + version+ return self.base_name++ def get_excl(self):+ """+ Return the patterns to exclude for finding the files in the top-level directory. Set the attribute *excl*+ to change the default value::++ def dist(ctx):+ ctx.excl = 'build **/*.o **/*.class'++ :rtype: string+ """+ try:+ return self.excl+ except AttributeError:+ self.excl = Node.exclude_regs + ' **/waf-1.7.* **/.waf-1.7* **/waf3-1.7.* **/.waf3-1.7* **/*~ **/*.rej **/*.orig **/*.pyc **/*.pyo **/*.bak **/*.swp **/.lock-w*'+ nd = self.root.find_node(Context.out_dir)+ if nd:+ self.excl += ' ' + nd.path_from(self.base_path)+ return self.excl++ def get_files(self):+ """+ The files to package are searched automatically by :py:func:`waflib.Node.Node.ant_glob`. Set+ *files* to prevent this behaviour::++ def dist(ctx):+ ctx.files = ctx.path.find_node('wscript')++ The files are searched from the directory 'base_path', to change it, set::++ def dist(ctx):+ ctx.base_path = path++ :rtype: list of :py:class:`waflib.Node.Node`+ """+ try:+ files = self.files+ except AttributeError:+ files = self.base_path.ant_glob('**/*', excl=self.get_excl())+ return files+++def dist(ctx):+ '''makes a tarball for redistributing the sources'''+ pass++class DistCheck(Dist):+ """+ Create an archive of the project, and try to build the project in a temporary directory::++ $ waf distcheck+ """++ fun = 'distcheck'+ cmd = 'distcheck'++ def execute(self):+ """+ See :py:func:`waflib.Context.Context.execute`+ """+ self.recurse([os.path.dirname(Context.g_module.root_path)])+ self.archive()+ self.check()++ def check(self):+ """+ Create the archive, uncompress it and try to build the project+ """+ import tempfile, tarfile++ t = None+ try:+ t = tarfile.open(self.get_arch_name())+ for x in t:+ t.extract(x)+ finally:+ if t:+ t.close()++ cfg = []++ if Options.options.distcheck_args:+ cfg = shlex.split(Options.options.distcheck_args)+ else:+ cfg = [x for x in sys.argv if x.startswith('-')]++ instdir = tempfile.mkdtemp('.inst', self.get_base_name())+ ret = Utils.subprocess.Popen([sys.argv[0], 'configure', 'install', 'uninstall', '--destdir=' + instdir] + cfg, cwd=self.get_base_name()).wait()+ if ret:+ raise Errors.WafError('distcheck failed with code %i' % ret)++ if os.path.exists(instdir):+ raise Errors.WafError('distcheck succeeded, but files were left in %s' % instdir)++ shutil.rmtree(self.get_base_name())+++def distcheck(ctx):+ '''checks if the project compiles (tarball from 'dist')'''+ pass++def update(ctx):+ '''updates the plugins from the *waflib/extras* directory'''+ lst = Options.options.files.split(',')+ if not lst:+ lst = [x for x in Utils.listdir(Context.waf_dir + '/waflib/extras') if x.endswith('.py')]+ for x in lst:+ tool = x.replace('.py', '')+ try:+ Configure.download_tool(tool, force=True, ctx=ctx)+ except Errors.WafError:+ Logs.error('Could not find the tool %s in the remote repository' % x)++def autoconfigure(execute_method):+ """+ Decorator used to set the commands that can be configured automatically+ """+ def execute(self):+ if not Configure.autoconfig:+ return execute_method(self)++ env = ConfigSet.ConfigSet()+ do_config = False+ try:+ env.load(os.path.join(Context.top_dir, Options.lockfile))+ except Exception:+ Logs.warn('Configuring the project')+ do_config = True+ else:+ if env.run_dir != Context.run_dir:+ do_config = True+ else:+ h = 0+ for f in env['files']:+ h = hash((h, Utils.readf(f, 'rb')))+ do_config = h != env.hash++ if do_config:+ Options.commands.insert(0, self.cmd)+ Options.commands.insert(0, 'configure')+ return++ return execute_method(self)+ return execute+Build.BuildContext.execute = autoconfigure(Build.BuildContext.execute)+new file mode 100644@@ -0,0 +1,1248 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""+Tasks represent atomic operations such as processes.+"""++import os, shutil, re, tempfile+from waflib import Utils, Logs, Errors++# task states+NOT_RUN = 0+"""The task was not executed yet"""++MISSING = 1+"""The task has been executed but the files have not been created"""++CRASHED = 2+"""The task execution returned a non-zero exit status"""++EXCEPTION = 3+"""An exception occured in the task execution"""++SKIPPED = 8+"""The task did not have to be executed"""++SUCCESS = 9+"""The task was successfully executed"""++ASK_LATER = -1+"""The task is not ready to be executed"""++SKIP_ME = -2+"""The task does not need to be executed"""++RUN_ME = -3+"""The task must be executed"""++COMPILE_TEMPLATE_SHELL = '''+def f(tsk):+ env = tsk.env+ gen = tsk.generator+ bld = gen.bld+ wd = getattr(tsk, 'cwd', None)+ p = env.get_flat+ tsk.last_cmd = cmd = \'\'\' %s \'\'\' % s+ return tsk.exec_command(cmd, cwd=wd, env=env.env or None)+'''++COMPILE_TEMPLATE_NOSHELL = '''+def f(tsk):+ env = tsk.env+ gen = tsk.generator+ bld = gen.bld+ wd = getattr(tsk, 'cwd', None)+ def to_list(xx):+ if isinstance(xx, str): return [xx]+ return xx+ tsk.last_cmd = lst = []+ %s+ lst = [x for x in lst if x]+ return tsk.exec_command(lst, cwd=wd, env=env.env or None)+'''++def cache_outputs(cls):+ """+ Task class decorator applied to all task classes by default unless they define the attribute 'nocache'::++ from waflib import Task+ class foo(Task.Task):+ nocache = True++ If bld.cache_global is defined and if the task instances produces output nodes,+ the files will be copied into a folder in the cache directory++ The files may also be retrieved from that folder, if it exists+ """+ m1 = cls.run+ def run(self):+ bld = self.generator.bld+ if bld.cache_global and not bld.nocache:+ if self.can_retrieve_cache():+ return 0+ return m1(self)+ cls.run = run++ m2 = cls.post_run+ def post_run(self):+ bld = self.generator.bld+ ret = m2(self)+ if bld.cache_global and not bld.nocache:+ self.put_files_cache()+ return ret+ cls.post_run = post_run++ return cls+++classes = {}+"class tasks created by user scripts or Waf tools are kept in this dict name -> class object"++class store_task_type(type):+ """+ Metaclass: store the task classes into :py:const:`waflib.Task.classes`, or to the dict pointed+ by the class attribute 'register'.+ The attribute 'run_str' will be processed to compute a method 'run' on the task class+ The decorator :py:func:`waflib.Task.cache_outputs` is also applied to the class+ """+ def __init__(cls, name, bases, dict):+ super(store_task_type, cls).__init__(name, bases, dict)+ name = cls.__name__++ if name.endswith('_task'):+ name = name.replace('_task', '')+ if name != 'evil' and name != 'TaskBase':+ global classes++ if getattr(cls, 'run_str', None):+ # if a string is provided, convert it to a method+ (f, dvars) = compile_fun(cls.run_str, cls.shell)+ cls.hcode = cls.run_str+ cls.run_str = None+ cls.run = f+ cls.vars = list(set(cls.vars + dvars))+ cls.vars.sort()+ elif getattr(cls, 'run', None) and not 'hcode' in cls.__dict__:+ # getattr(cls, 'hcode') would look in the upper classes+ cls.hcode = Utils.h_fun(cls.run)++ if not getattr(cls, 'nocache', None):+ cls = cache_outputs(cls)++ # be creative+ getattr(cls, 'register', classes)[name] = cls++evil = store_task_type('evil', (object,), {})+"Base class provided to avoid writing a metaclass, so the code can run in python 2.6 and 3.x unmodified"++class TaskBase(evil):+ """+ Base class for all Waf tasks, which should be seen as an interface.+ For illustration purposes, instances of this class will execute the attribute+ 'fun' in :py:meth:`waflib.Task.TaskBase.run`. When in doubt, create+ subclasses of :py:class:`waflib.Task.Task` instead.++ Subclasses should override these methods:++ #. __str__: string to display to the user+ #. runnable_status: ask the task if it should be run, skipped, or if we have to ask later+ #. run: let threads execute the task+ #. post_run: let threads update the data regarding the task (cache)+ """++ color = 'GREEN'+ """Color for the console display, see :py:const:`waflib.Logs.colors_lst`"""++ ext_in = []+ """File extensions that objects of this task class might use"""++ ext_out = []+ """File extensions that objects of this task class might create"""++ before = []+ """List of task class names to execute before instances of this class"""++ after = []+ """List of task class names to execute after instances of this class"""++ hcode = ''+ """String representing an additional hash for the class representation"""++ def __init__(self, *k, **kw):+ """+ The base task class requires a task generator, which will be itself if missing+ """+ self.hasrun = NOT_RUN+ try:+ self.generator = kw['generator']+ except KeyError:+ self.generator = self++ def __repr__(self):+ "for debugging purposes"+ return '\n\t{task %r: %s %s}' % (self.__class__.__name__, id(self), str(getattr(self, 'fun', '')))++ def __str__(self):+ "string to display to the user"+ if hasattr(self, 'fun'):+ return 'executing: %s\n' % self.fun.__name__+ return self.__class__.__name__ + '\n'++ def __hash__(self):+ "Very fast hashing scheme but not persistent (replace/implement in subclasses and see :py:meth:`waflib.Task.Task.uid`)"+ return id(self)++ def exec_command(self, cmd, **kw):+ """+ Wrapper for :py:meth:`waflib.Context.Context.exec_command` which sets a current working directory to ``build.variant_dir``++ :return: the return code+ :rtype: int+ """+ bld = self.generator.bld+ try:+ if not kw.get('cwd', None):+ kw['cwd'] = bld.cwd+ except AttributeError:+ bld.cwd = kw['cwd'] = bld.variant_dir+ return bld.exec_command(cmd, **kw)++ def runnable_status(self):+ """+ State of the task++ :return: a task state in :py:const:`waflib.Task.RUN_ME`, :py:const:`waflib.Task.SKIP_ME` or :py:const:`waflib.Task.ASK_LATER`.+ :rtype: int+ """+ return RUN_ME++ def process(self):+ """+ Assume that the task has had a new attribute ``master`` which is an instance of :py:class:`waflib.Runner.Parallel`.+ Execute the task and then put it back in the queue :py:attr:`waflib.Runner.Parallel.out` (may be replaced by subclassing).+ """+ m = self.master+ if m.stop:+ m.out.put(self)+ return++ # remove the task signature immediately before it is executed+ # in case of failure the task will be executed again+ try:+ del self.generator.bld.task_sigs[self.uid()]+ except KeyError:+ pass++ try:+ self.generator.bld.returned_tasks.append(self)+ self.log_display(self.generator.bld)+ ret = self.run()+ except Exception:+ self.err_msg = Utils.ex_stack()+ self.hasrun = EXCEPTION++ # TODO cleanup+ m.error_handler(self)+ m.out.put(self)+ return++ if ret:+ self.err_code = ret+ self.hasrun = CRASHED+ else:+ try:+ self.post_run()+ except Errors.WafError:+ pass+ except Exception:+ self.err_msg = Utils.ex_stack()+ self.hasrun = EXCEPTION+ else:+ self.hasrun = SUCCESS+ if self.hasrun != SUCCESS:+ m.error_handler(self)++ m.out.put(self)++ def run(self):+ """+ Called by threads to execute the tasks. The default is empty and meant to be overridden in subclasses.+ It is a bad idea to create nodes in this method (so, no node.ant_glob)++ :rtype: int+ """+ if hasattr(self, 'fun'):+ return self.fun(self)+ return 0++ def post_run(self):+ "Update the cache files (executed by threads). Override in subclasses."+ pass++ def log_display(self, bld):+ "Write the execution status on the context logger"+ bld.to_log(self.display())++ def display(self):+ """+ Return an execution status for the console, the progress bar, or the IDE output.++ :rtype: string+ """+ col1 = Logs.colors(self.color)+ col2 = Logs.colors.NORMAL+ master = self.master++ def cur():+ # the current task position, computed as late as possible+ tmp = -1+ if hasattr(master, 'ready'):+ tmp -= master.ready.qsize()+ return master.processed + tmp++ if self.generator.bld.progress_bar == 1:+ return self.generator.bld.progress_line(cur(), master.total, col1, col2)++ if self.generator.bld.progress_bar == 2:+ ela = str(self.generator.bld.timer)+ try:+ ins = ','.join([n.name for n in self.inputs])+ except AttributeError:+ ins = ''+ try:+ outs = ','.join([n.name for n in self.outputs])+ except AttributeError:+ outs = ''+ return '|Total %s|Current %s|Inputs %s|Outputs %s|Time %s|\n' % (master.total, cur(), ins, outs, ela)++ s = str(self)+ if not s:+ return None++ total = master.total+ n = len(str(total))+ fs = '[%%%dd/%%%dd] %%s%%s%%s' % (n, n)+ return fs % (cur(), total, col1, s, col2)++ def attr(self, att, default=None):+ """+ Retrieve an attribute from the instance or from the class.++ :param att: variable name+ :type att: string+ :param default: default value+ """+ ret = getattr(self, att, self)+ if ret is self: return getattr(self.__class__, att, default)+ return ret++ def hash_constraints(self):+ """+ Identify a task type for all the constraints relevant for the scheduler: precedence, file production++ :return: a hash value+ :rtype: string+ """+ cls = self.__class__+ tup = (str(cls.before), str(cls.after), str(cls.ext_in), str(cls.ext_out), cls.__name__, cls.hcode)+ h = hash(tup)+ return h++ def format_error(self):+ """+ Error message to display to the user when a build fails++ :rtype: string+ """+ msg = getattr(self, 'last_cmd', '')+ name = getattr(self.generator, 'name', '')+ if getattr(self, "err_msg", None):+ return self.err_msg+ elif not self.hasrun:+ return 'task in %r was not executed for some reason: %r' % (name, self)+ elif self.hasrun == CRASHED:+ try:+ return ' -> task in %r failed (exit status %r): %r\n%r' % (name, self.err_code, self, msg)+ except AttributeError:+ return ' -> task in %r failed: %r\n%r' % (name, self, msg)+ elif self.hasrun == MISSING:+ return ' -> missing files in %r: %r\n%r' % (name, self, msg)+ else:+ return 'invalid status for task in %r: %r' % (name, self.hasrun)++ def colon(self, var1, var2):+ """+ private function for the moment++ used for scriptlet expressions such as ${FOO_ST:FOO}, for example, if+ env.FOO_ST = ['-a', '-b']+ env.FOO = ['1', '2']+ then the result will be ['-a', '-b', '1', '-a', '-b', '2']+ """+ tmp = self.env[var1]+ if isinstance(var2, str):+ it = self.env[var2]+ else:+ it = var2+ if isinstance(tmp, str):+ return [tmp % x for x in it]+ else:+ if Logs.verbose and not tmp and it:+ Logs.warn('Missing env variable %r for task %r (generator %r)' % (var1, self, self.generator))+ lst = []+ for y in it:+ lst.extend(tmp)+ lst.append(y)+ return lst++class Task(TaskBase):+ """+ This class deals with the filesystem (:py:class:`waflib.Node.Node`). The method :py:class:`waflib.Task.Task.runnable_status`+ uses a hash value (from :py:class:`waflib.Task.Task.signature`) which is persistent from build to build. When the value changes,+ the task has to be executed. The method :py:class:`waflib.Task.Task.post_run` will assign the task signature to the output+ nodes (if present).+ """+ vars = []+ """Variables to depend on (class attribute used for :py:meth:`waflib.Task.Task.sig_vars`)"""++ shell = False+ """Execute the command with the shell (class attribute)"""++ def __init__(self, *k, **kw):+ TaskBase.__init__(self, *k, **kw)++ self.env = kw['env']+ """ConfigSet object (make sure to provide one)"""++ self.inputs = []+ """List of input nodes, which represent the files used by the task instance"""++ self.outputs = []+ """List of output nodes, which represent the files created by the task instance"""++ self.dep_nodes = []+ """List of additional nodes to depend on"""++ self.run_after = set([])+ """Set of tasks that must be executed before this one"""++ # Additionally, you may define the following+ #self.dep_vars = 'PREFIX DATADIR'++ def __str__(self):+ "string to display to the user"+ env = self.env+ src_str = ' '.join([a.nice_path() for a in self.inputs])+ tgt_str = ' '.join([a.nice_path() for a in self.outputs])+ if self.outputs: sep = ' -> '+ else: sep = ''+ return '%s: %s%s%s\n' % (self.__class__.__name__.replace('_task', ''), src_str, sep, tgt_str)++ def __repr__(self):+ "for debugging purposes"+ try:+ ins = ",".join([x.name for x in self.inputs])+ outs = ",".join([x.name for x in self.outputs])+ except AttributeError:+ ins = ",".join([str(x) for x in self.inputs])+ outs = ",".join([str(x) for x in self.outputs])+ return "".join(['\n\t{task %r: ' % id(self), self.__class__.__name__, " ", ins, " -> ", outs, '}'])++ def uid(self):+ """+ Return an identifier used to determine if tasks are up-to-date. Since the+ identifier will be stored between executions, it must be:++ - unique: no two tasks return the same value (for a given build context)+ - the same for a given task instance++ By default, the node paths, the class name, and the function are used+ as inputs to compute a hash.++ The pointer to the object (python built-in 'id') will change between build executions,+ and must be avoided in such hashes.++ :return: hash value+ :rtype: string+ """+ try:+ return self.uid_+ except AttributeError:+ # this is not a real hot zone, but we want to avoid surprises here+ m = Utils.md5()+ up = m.update+ up(self.__class__.__name__.encode())+ for x in self.inputs + self.outputs:+ up(x.abspath().encode())+ self.uid_ = m.digest()+ return self.uid_++ def set_inputs(self, inp):+ """+ Append the nodes to the *inputs*++ :param inp: input nodes+ :type inp: node or list of nodes+ """+ if isinstance(inp, list): self.inputs += inp+ else: self.inputs.append(inp)++ def set_outputs(self, out):+ """+ Append the nodes to the *outputs*++ :param out: output nodes+ :type out: node or list of nodes+ """+ if isinstance(out, list): self.outputs += out+ else: self.outputs.append(out)++ def set_run_after(self, task):+ """+ Run this task only after *task*. Affect :py:meth:`waflib.Task.runnable_status`+ You probably want to use tsk.run_after.add(task) directly++ :param task: task+ :type task: :py:class:`waflib.Task.Task`+ """+ assert isinstance(task, TaskBase)+ self.run_after.add(task)++ def signature(self):+ """+ Task signatures are stored between build executions, they are use to track the changes+ made to the input nodes (not to the outputs!). The signature hashes data from various sources:++ * explicit dependencies: files listed in the inputs (list of node objects) :py:meth:`waflib.Task.Task.sig_explicit_deps`+ * implicit dependencies: list of nodes returned by scanner methods (when present) :py:meth:`waflib.Task.Task.sig_implicit_deps`+ * hashed data: variables/values read from task.__class__.vars/task.env :py:meth:`waflib.Task.Task.sig_vars`++ If the signature is expected to give a different result, clear the cache kept in ``self.cache_sig``::++ from waflib import Task+ class cls(Task.Task):+ def signature(self):+ sig = super(Task.Task, self).signature()+ delattr(self, 'cache_sig')+ return super(Task.Task, self).signature()+ """+ try: return self.cache_sig+ except AttributeError: pass++ self.m = Utils.md5()+ self.m.update(self.hcode.encode())++ # explicit deps+ self.sig_explicit_deps()++ # env vars+ self.sig_vars()++ # implicit deps / scanner results+ if self.scan:+ try:+ self.sig_implicit_deps()+ except Errors.TaskRescan:+ return self.signature()++ ret = self.cache_sig = self.m.digest()+ return ret++ def runnable_status(self):+ """+ Override :py:meth:`waflib.Task.TaskBase.runnable_status` to determine if the task is ready+ to be run (:py:attr:`waflib.Task.Task.run_after`)+ """+ #return 0 # benchmarking++ for t in self.run_after:+ if not t.hasrun:+ return ASK_LATER++ bld = self.generator.bld++ # first compute the signature+ try:+ new_sig = self.signature()+ except Errors.TaskNotReady:+ return ASK_LATER++ # compare the signature to a signature computed previously+ key = self.uid()+ try:+ prev_sig = bld.task_sigs[key]+ except KeyError:+ Logs.debug("task: task %r must run as it was never run before or the task code changed" % self)+ return RUN_ME++ # compare the signatures of the outputs+ for node in self.outputs:+ try:+ if node.sig != new_sig:+ return RUN_ME+ except AttributeError:+ Logs.debug("task: task %r must run as the output nodes do not exist" % self)+ return RUN_ME++ if new_sig != prev_sig:+ return RUN_ME+ return SKIP_ME++ def post_run(self):+ """+ Called after successful execution to update the cache data :py:class:`waflib.Node.Node` sigs+ and :py:attr:`waflib.Build.BuildContext.task_sigs`.++ The node signature is obtained from the task signature, but the output nodes may also get the signature+ of their contents. See the class decorator :py:func:`waflib.Task.update_outputs` if you need this behaviour.+ """+ bld = self.generator.bld+ sig = self.signature()++ for node in self.outputs:+ # check if the node exists ..+ try:+ os.stat(node.abspath())+ except OSError:+ self.hasrun = MISSING+ self.err_msg = '-> missing file: %r' % node.abspath()+ raise Errors.WafError(self.err_msg)++ # important, store the signature for the next run+ node.sig = sig++ bld.task_sigs[self.uid()] = self.cache_sig++ def sig_explicit_deps(self):+ """+ Used by :py:meth:`waflib.Task.Task.signature`, hash :py:attr:`waflib.Task.Task.inputs`+ and :py:attr:`waflib.Task.Task.dep_nodes` signatures.++ :rtype: hash value+ """+ bld = self.generator.bld+ upd = self.m.update++ # the inputs+ for x in self.inputs + self.dep_nodes:+ try:+ upd(x.get_bld_sig())+ except (AttributeError, TypeError):+ raise Errors.WafError('Missing node signature for %r (required by %r)' % (x, self))++ # manual dependencies, they can slow down the builds+ if bld.deps_man:+ additional_deps = bld.deps_man+ for x in self.inputs + self.outputs:+ try:+ d = additional_deps[id(x)]+ except KeyError:+ continue++ for v in d:+ if isinstance(v, bld.root.__class__):+ try:+ v = v.get_bld_sig()+ except AttributeError:+ raise Errors.WafError('Missing node signature for %r (required by %r)' % (v, self))+ elif hasattr(v, '__call__'):+ v = v() # dependency is a function, call it+ upd(v)++ return self.m.digest()++ def sig_vars(self):+ """+ Used by :py:meth:`waflib.Task.Task.signature`, hash :py:attr:`waflib.Task.Task.env` variables/values++ :rtype: hash value+ """+ bld = self.generator.bld+ env = self.env+ upd = self.m.update++ # dependencies on the environment vars+ act_sig = bld.hash_env_vars(env, self.__class__.vars)+ upd(act_sig)++ # additional variable dependencies, if provided+ dep_vars = getattr(self, 'dep_vars', None)+ if dep_vars:+ upd(bld.hash_env_vars(env, dep_vars))++ return self.m.digest()++ scan = None+ """+ This method, when provided, returns a tuple containing:++ * a list of nodes corresponding to real files+ * a list of names for files not found in path_lst++ For example::++ from waflib.Task import Task+ class mytask(Task):+ def scan(self, node):+ return ((), ())++ The first and second lists are stored in :py:attr:`waflib.Build.BuildContext.node_deps` and+ :py:attr:`waflib.Build.BuildContext.raw_deps` respectively.+ """++ def sig_implicit_deps(self):+ """+ Used by :py:meth:`waflib.Task.Task.signature` hashes node signatures obtained by scanning for dependencies (:py:meth:`waflib.Task.Task.scan`).++ The exception :py:class:`waflib.Errors.TaskRescan` is thrown+ when a file has changed. When this occurs, :py:meth:`waflib.Task.Task.signature` is called+ once again, and this method will be executed once again, this time calling :py:meth:`waflib.Task.Task.scan`+ for searching the dependencies.++ :rtype: hash value+ """++ bld = self.generator.bld++ # get the task signatures from previous runs+ key = self.uid()+ prev = bld.task_sigs.get((key, 'imp'), [])++ # for issue #379+ if prev:+ try:+ if prev == self.compute_sig_implicit_deps():+ return prev+ except Exception:+ # when a file was renamed (IOError usually), remove the stale nodes (headers in folders without source files)+ # this will break the order calculation for headers created during the build in the source directory (should be uncommon)+ # the behaviour will differ when top != out+ for x in bld.node_deps.get(self.uid(), []):+ if x.is_child_of(bld.srcnode):+ try:+ os.stat(x.abspath())+ except OSError:+ try:+ del x.parent.children[x.name]+ except KeyError:+ pass+ del bld.task_sigs[(key, 'imp')]+ raise Errors.TaskRescan('rescan')++ # no previous run or the signature of the dependencies has changed, rescan the dependencies+ (nodes, names) = self.scan()+ if Logs.verbose:+ Logs.debug('deps: scanner for %s returned %s %s' % (str(self), str(nodes), str(names)))++ # store the dependencies in the cache+ bld.node_deps[key] = nodes+ bld.raw_deps[key] = names++ # might happen+ self.are_implicit_nodes_ready()++ # recompute the signature and return it+ try:+ bld.task_sigs[(key, 'imp')] = sig = self.compute_sig_implicit_deps()+ except Exception:+ if Logs.verbose:+ for k in bld.node_deps.get(self.uid(), []):+ try:+ k.get_bld_sig()+ except Exception:+ Logs.warn('Missing signature for node %r (may cause rebuilds)' % k)+ else:+ return sig++ def compute_sig_implicit_deps(self):+ """+ Used by :py:meth:`waflib.Task.Task.sig_implicit_deps` for computing the actual hash of the+ :py:class:`waflib.Node.Node` returned by the scanner.++ :return: hash value+ :rtype: string+ """++ upd = self.m.update++ bld = self.generator.bld++ self.are_implicit_nodes_ready()++ # scanner returns a node that does not have a signature+ # just *ignore* the error and let them figure out from the compiler output+ # waf -k behaviour+ for k in bld.node_deps.get(self.uid(), []):+ upd(k.get_bld_sig())+ return self.m.digest()++ def are_implicit_nodes_ready(self):+ """+ For each node returned by the scanner, see if there is a task behind it, and force the build order++ The performance impact on null builds is nearly invisible (1.66s->1.86s), but this is due to+ agressive caching (1.86s->28s)+ """+ bld = self.generator.bld+ try:+ cache = bld.dct_implicit_nodes+ except AttributeError:+ bld.dct_implicit_nodes = cache = {}++ try:+ dct = cache[bld.cur]+ except KeyError:+ dct = cache[bld.cur] = {}+ for tsk in bld.cur_tasks:+ for x in tsk.outputs:+ dct[x] = tsk++ modified = False+ for x in bld.node_deps.get(self.uid(), []):+ if x in dct:+ self.run_after.add(dct[x])+ modified = True++ if modified:+ for tsk in self.run_after:+ if not tsk.hasrun:+ #print "task is not ready..."+ raise Errors.TaskNotReady('not ready')++ def can_retrieve_cache(self):+ """+ Used by :py:meth:`waflib.Task.cache_outputs`++ Retrieve build nodes from the cache+ update the file timestamps to help cleaning the least used entries from the cache+ additionally, set an attribute 'cached' to avoid re-creating the same cache files++ Suppose there are files in `cache/dir1/file1` and `cache/dir2/file2`:++ #. read the timestamp of dir1+ #. try to copy the files+ #. look at the timestamp again, if it has changed, the data may have been corrupt (cache update by another process)+ #. should an exception occur, ignore the data+ """++ if not getattr(self, 'outputs', None):+ return None++ sig = self.signature()+ ssig = Utils.to_hex(self.uid()) + Utils.to_hex(sig)++ # first try to access the cache folder for the task+ dname = os.path.join(self.generator.bld.cache_global, ssig)+ try:+ t1 = os.stat(dname).st_mtime+ except OSError:+ return None++ for node in self.outputs:+ orig = os.path.join(dname, node.name)+ try:+ shutil.copy2(orig, node.abspath())+ # mark the cache file as used recently (modified)+ os.utime(orig, None)+ except (OSError, IOError):+ Logs.debug('task: failed retrieving file')+ return None++ # is it the same folder?+ try:+ t2 = os.stat(dname).st_mtime+ except OSError:+ return None++ if t1 != t2:+ return None++ for node in self.outputs:+ node.sig = sig+ if self.generator.bld.progress_bar < 1:+ self.generator.bld.to_log('restoring from cache %r\n' % node.abspath())++ self.cached = True+ return True++ def put_files_cache(self):+ """+ Used by :py:func:`waflib.Task.cache_outputs` to store the build files in the cache+ """++ # file caching, if possible+ # try to avoid data corruption as much as possible+ if getattr(self, 'cached', None):+ return None+ if not getattr(self, 'outputs', None):+ return None++ sig = self.signature()+ ssig = Utils.to_hex(self.uid()) + Utils.to_hex(sig)+ dname = os.path.join(self.generator.bld.cache_global, ssig)+ tmpdir = tempfile.mkdtemp(prefix=self.generator.bld.cache_global + os.sep + 'waf')++ try:+ shutil.rmtree(dname)+ except Exception:+ pass++ try:+ for node in self.outputs:+ dest = os.path.join(tmpdir, node.name)+ shutil.copy2(node.abspath(), dest)+ except (OSError, IOError):+ try:+ shutil.rmtree(tmpdir)+ except Exception:+ pass+ else:+ try:+ os.rename(tmpdir, dname)+ except OSError:+ try:+ shutil.rmtree(tmpdir)+ except Exception:+ pass+ else:+ try:+ os.chmod(dname, Utils.O755)+ except Exception:+ pass++def is_before(t1, t2):+ """+ Return a non-zero value if task t1 is to be executed before task t2::++ t1.ext_out = '.h'+ t2.ext_in = '.h'+ t2.after = ['t1']+ t1.before = ['t2']+ waflib.Task.is_before(t1, t2) # True++ :param t1: task+ :type t1: :py:class:`waflib.Task.TaskBase`+ :param t2: task+ :type t2: :py:class:`waflib.Task.TaskBase`+ """+ to_list = Utils.to_list+ for k in to_list(t2.ext_in):+ if k in to_list(t1.ext_out):+ return 1++ if t1.__class__.__name__ in to_list(t2.after):+ return 1++ if t2.__class__.__name__ in to_list(t1.before):+ return 1++ return 0++def set_file_constraints(tasks):+ """+ Adds tasks to the task 'run_after' attribute based on the task inputs and outputs++ :param tasks: tasks+ :type tasks: list of :py:class:`waflib.Task.TaskBase`+ """+ ins = Utils.defaultdict(set)+ outs = Utils.defaultdict(set)+ for x in tasks:+ for a in getattr(x, 'inputs', []) + getattr(x, 'dep_nodes', []):+ ins[id(a)].add(x)+ for a in getattr(x, 'outputs', []):+ outs[id(a)].add(x)++ links = set(ins.keys()).intersection(outs.keys())+ for k in links:+ for a in ins[k]:+ a.run_after.update(outs[k])++def set_precedence_constraints(tasks):+ """+ Add tasks to the task 'run_after' attribute based on the after/before/ext_out/ext_in attributes++ :param tasks: tasks+ :type tasks: list of :py:class:`waflib.Task.TaskBase`+ """+ cstr_groups = Utils.defaultdict(list)+ for x in tasks:+ h = x.hash_constraints()+ cstr_groups[h].append(x)++ keys = list(cstr_groups.keys())+ maxi = len(keys)++ # this list should be short+ for i in range(maxi):+ t1 = cstr_groups[keys[i]][0]+ for j in range(i + 1, maxi):+ t2 = cstr_groups[keys[j]][0]++ # add the constraints based on the comparisons+ if is_before(t1, t2):+ a = i+ b = j+ elif is_before(t2, t1):+ a = j+ b = i+ else:+ continue++ aval = set(cstr_groups[keys[a]])+ for x in cstr_groups[keys[b]]:+ x.run_after.update(aval)++def funex(c):+ """+ Compile a function by 'exec'++ :param c: function to compile+ :type c: string+ :return: the function 'f' declared in the input string+ :rtype: function+ """+ dc = {}+ exec(c, dc)+ return dc['f']++reg_act = re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})", re.M)+def compile_fun_shell(line):+ """+ Create a compiled function to execute a process with the shell+ WARNING: this method may disappear anytime, so use compile_fun instead+ """++ extr = []+ def repl(match):+ g = match.group+ if g('dollar'): return "$"+ elif g('backslash'): return '\\\\'+ elif g('subst'): extr.append((g('var'), g('code'))); return "%s"+ return None++ line = reg_act.sub(repl, line) or line++ parm = []+ dvars = []+ app = parm.append+ for (var, meth) in extr:+ if var == 'SRC':+ if meth: app('tsk.inputs%s' % meth)+ else: app('" ".join([a.path_from(bld.bldnode) for a in tsk.inputs])')+ elif var == 'TGT':+ if meth: app('tsk.outputs%s' % meth)+ else: app('" ".join([a.path_from(bld.bldnode) for a in tsk.outputs])')+ elif meth:+ if meth.startswith(':'):+ m = meth[1:]+ if m == 'SRC':+ m = '[a.path_from(bld.bldnode) for a in tsk.inputs]'+ elif m == 'TGT':+ m = '[a.path_from(bld.bldnode) for a in tsk.outputs]'+ elif m[:3] not in ('tsk', 'gen', 'bld'):+ dvars.extend([var, meth[1:]])+ m = '%r' % m+ app('" ".join(tsk.colon(%r, %s))' % (var, m))+ else:+ app('%s%s' % (var, meth))+ else:+ if not var in dvars: dvars.append(var)+ app("p('%s')" % var)+ if parm: parm = "%% (%s) " % (',\n\t\t'.join(parm))+ else: parm = ''++ c = COMPILE_TEMPLATE_SHELL % (line, parm)++ Logs.debug('action: %s' % c.strip().splitlines())+ return (funex(c), dvars)++def compile_fun_noshell(line):+ """+ Create a compiled function to execute a process without the shell+ WARNING: this method may disappear anytime, so use compile_fun instead+ """+ extr = []+ def repl(match):+ g = match.group+ if g('dollar'): return "$"+ elif g('subst'): extr.append((g('var'), g('code'))); return "<<|@|>>"+ return None++ line2 = reg_act.sub(repl, line)+ params = line2.split('<<|@|>>')+ assert(extr)++ buf = []+ dvars = []+ app = buf.append+ for x in range(len(extr)):+ params[x] = params[x].strip()+ if params[x]:+ app("lst.extend(%r)" % params[x].split())+ (var, meth) = extr[x]+ if var == 'SRC':+ if meth: app('lst.append(tsk.inputs%s)' % meth)+ else: app("lst.extend([a.path_from(bld.bldnode) for a in tsk.inputs])")+ elif var == 'TGT':+ if meth: app('lst.append(tsk.outputs%s)' % meth)+ else: app("lst.extend([a.path_from(bld.bldnode) for a in tsk.outputs])")+ elif meth:+ if meth.startswith(':'):+ m = meth[1:]+ if m == 'SRC':+ m = '[a.path_from(bld.bldnode) for a in tsk.inputs]'+ elif m == 'TGT':+ m = '[a.path_from(bld.bldnode) for a in tsk.outputs]'+ elif m[:3] not in ('tsk', 'gen', 'bld'):+ dvars.extend([var, m])+ m = '%r' % m+ app('lst.extend(tsk.colon(%r, %s))' % (var, m))+ else:+ app('lst.extend(gen.to_list(%s%s))' % (var, meth))+ else:+ app('lst.extend(to_list(env[%r]))' % var)+ if not var in dvars: dvars.append(var)++ if extr:+ if params[-1]:+ app("lst.extend(%r)" % params[-1].split())+ fun = COMPILE_TEMPLATE_NOSHELL % "\n\t".join(buf)+ Logs.debug('action: %s' % fun.strip().splitlines())+ return (funex(fun), dvars)++def compile_fun(line, shell=False):+ """+ Parse a string expression such as "${CC} ${SRC} -o ${TGT}" and return a pair containing:++ * the function created (compiled) for use as :py:meth:`waflib.Task.TaskBase.run`+ * the list of variables that imply a dependency from self.env++ for example::++ from waflib.Task import compile_fun+ compile_fun('cxx', '${CXX} -o ${TGT[0]} ${SRC} -I ${SRC[0].parent.bldpath()}')++ def build(bld):+ bld(source='wscript', rule='echo "foo\\${SRC[0].name}\\bar"')++ The env variables (CXX, ..) on the task must not hold dicts (order)+ The reserved keywords *TGT* and *SRC* represent the task input and output nodes++ """+ if line.find('<') > 0 or line.find('>') > 0 or line.find('&&') > 0:+ shell = True++ if shell:+ return compile_fun_shell(line)+ else:+ return compile_fun_noshell(line)++def task_factory(name, func=None, vars=None, color='GREEN', ext_in=[], ext_out=[], before=[], after=[], shell=False, scan=None):+ """+ Deprecated. Return a new task subclass with the function ``run`` compiled from the line given.+ Provided for compatibility with waf 1.4-1.5, when we did not have the metaclass to register new classes (will be removed in Waf 1.8)++ :param func: method run+ :type func: string or function+ :param vars: list of variables to hash+ :type vars: list of string+ :param color: color to use+ :type color: string+ :param shell: when *func* is a string, enable/disable the use of the shell+ :type shell: bool+ :param scan: method scan+ :type scan: function+ :rtype: :py:class:`waflib.Task.Task`+ """++ params = {+ 'vars': vars or [], # function arguments are static, and this one may be modified by the class+ 'color': color,+ 'name': name,+ 'ext_in': Utils.to_list(ext_in),+ 'ext_out': Utils.to_list(ext_out),+ 'before': Utils.to_list(before),+ 'after': Utils.to_list(after),+ 'shell': shell,+ 'scan': scan,+ }++ if isinstance(func, str):+ params['run_str'] = func+ else:+ params['run'] = func++ cls = type(Task)(name, (Task,), params)+ global classes+ classes[name] = cls+ return cls+++def always_run(cls):+ """+ Task class decorator++ Set all task instances of this class to be executed whenever a build is started+ The task signature is calculated, but the result of the comparation between+ task signatures is bypassed+ """+ old = cls.runnable_status+ def always(self):+ ret = old(self)+ if ret == SKIP_ME:+ ret = RUN_ME+ return ret+ cls.runnable_status = always+ return cls++def update_outputs(cls):+ """+ Task class decorator++ If you want to create files in the source directory. For example, to keep *foo.txt* in the source+ directory, create it first and declare::++ def build(bld):+ bld(rule='cp ${SRC} ${TGT}', source='wscript', target='foo.txt', update_outputs=True)+ """+ old_post_run = cls.post_run+ def post_run(self):+ old_post_run(self)+ for node in self.outputs:+ node.sig = Utils.h_file(node.abspath())+ self.generator.bld.task_sigs[node.abspath()] = self.uid() # issue #1017+ cls.post_run = post_run+++ old_runnable_status = cls.runnable_status+ def runnable_status(self):+ status = old_runnable_status(self)+ if status != RUN_ME:+ return status++ try:+ # by default, we check that the output nodes have the signature of the task+ # perform a second check, returning 'SKIP_ME' as we are expecting that+ # the signatures do not match+ bld = self.generator.bld+ prev_sig = bld.task_sigs[self.uid()]+ if prev_sig == self.signature():+ for x in self.outputs:+ if not x.sig or bld.task_sigs[x.abspath()] != self.uid():+ return RUN_ME+ return SKIP_ME+ except KeyError:+ pass+ except IndexError:+ pass+ except AttributeError:+ pass+ return RUN_ME+ cls.runnable_status = runnable_status++ return cls++new file mode 100644@@ -0,0 +1,817 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""+Task generators++The class :py:class:`waflib.TaskGen.task_gen` encapsulates the creation of task objects (low-level code)+The instances can have various parameters, but the creation of task nodes (Task.py)+is always postponed. To achieve this, various methods are called from the method "apply"+++"""++import copy, re, os+from waflib import Task, Utils, Logs, Errors, ConfigSet, Node++feats = Utils.defaultdict(set)+"""remember the methods declaring features"""++class task_gen(object):+ """+ Instances of this class create :py:class:`waflib.Task.TaskBase` when+ calling the method :py:meth:`waflib.TaskGen.task_gen.post` from the main thread.+ A few notes:++ * The methods to call (*self.meths*) can be specified dynamically (removing, adding, ..)+ * The 'features' are used to add methods to self.meths and then execute them+ * The attribute 'path' is a node representing the location of the task generator+ * The tasks created are added to the attribute *tasks*+ * The attribute 'idx' is a counter of task generators in the same path+ """++ mappings = {}+ prec = Utils.defaultdict(list)++ def __init__(self, *k, **kw):+ """+ The task generator objects predefine various attributes (source, target) for possible+ processing by process_rule (make-like rules) or process_source (extensions, misc methods)++ The tasks are stored on the attribute 'tasks'. They are created by calling methods+ listed in self.meths *or* referenced in the attribute features+ A topological sort is performed to ease the method re-use.++ The extra key/value elements passed in kw are set as attributes+ """++ # so we will have to play with directed acyclic graphs+ # detect cycles, etc+ self.source = ''+ self.target = ''++ self.meths = []+ """+ List of method names to execute (it is usually a good idea to avoid touching this)+ """++ self.prec = Utils.defaultdict(list)+ """+ Precedence table for sorting the methods in self.meths+ """++ self.mappings = {}+ """+ List of mappings {extension -> function} for processing files by extension+ """++ self.features = []+ """+ List of feature names for bringing new methods in+ """++ self.tasks = []+ """+ List of tasks created.+ """++ if not 'bld' in kw:+ # task generators without a build context :-/+ self.env = ConfigSet.ConfigSet()+ self.idx = 0+ self.path = None+ else:+ self.bld = kw['bld']+ self.env = self.bld.env.derive()+ self.path = self.bld.path # emulate chdir when reading scripts++ # provide a unique id+ try:+ self.idx = self.bld.idx[id(self.path)] = self.bld.idx.get(id(self.path), 0) + 1+ except AttributeError:+ self.bld.idx = {}+ self.idx = self.bld.idx[id(self.path)] = 1++ for key, val in kw.items():+ setattr(self, key, val)++ def __str__(self):+ """for debugging purposes"""+ return "<task_gen %r declared in %s>" % (self.name, self.path.abspath())++ def __repr__(self):+ """for debugging purposes"""+ lst = []+ for x in self.__dict__.keys():+ if x not in ['env', 'bld', 'compiled_tasks', 'tasks']:+ lst.append("%s=%s" % (x, repr(getattr(self, x))))+ return "bld(%s) in %s" % (", ".join(lst), self.path.abspath())++ def get_name(self):+ """+ If not set, the name is computed from the target name::++ def build(bld):+ x = bld(name='foo')+ x.get_name() # foo+ y = bld(target='bar')+ y.get_name() # bar++ :rtype: string+ :return: name of this task generator+ """+ try:+ return self._name+ except AttributeError:+ if isinstance(self.target, list):+ lst = [str(x) for x in self.target]+ name = self._name = ','.join(lst)+ else:+ name = self._name = str(self.target)+ return name+ def set_name(self, name):+ self._name = name++ name = property(get_name, set_name)++ def to_list(self, val):+ """+ Ensure that a parameter is a list++ :type val: string or list of string+ :param val: input to return as a list+ :rtype: list+ """+ if isinstance(val, str): return val.split()+ else: return val++ def post(self):+ """+ Create task objects. The following operations are performed:++ #. The body of this method is called only once and sets the attribute ``posted``+ #. The attribute ``features`` is used to add more methods in ``self.meths``+ #. The methods are sorted by the precedence table ``self.prec`` or `:waflib:attr:waflib.TaskGen.task_gen.prec`+ #. The methods are then executed in order+ #. The tasks created are added to :py:attr:`waflib.TaskGen.task_gen.tasks`+ """++ # we could add a decorator to let the task run once, but then python 2.3 will be difficult to support+ if getattr(self, 'posted', None):+ #error("OBJECT ALREADY POSTED" + str( self))+ return False+ self.posted = True++ keys = set(self.meths)++ # add the methods listed in the features+ self.features = Utils.to_list(self.features)+ for x in self.features + ['*']:+ st = feats[x]+ if not st:+ if not x in Task.classes:+ Logs.warn('feature %r does not exist - bind at least one method to it' % x)+ keys.update(list(st)) # ironpython 2.7 wants the cast to list++ # copy the precedence table+ prec = {}+ prec_tbl = self.prec or task_gen.prec+ for x in prec_tbl:+ if x in keys:+ prec[x] = prec_tbl[x]++ # elements disconnected+ tmp = []+ for a in keys:+ for x in prec.values():+ if a in x: break+ else:+ tmp.append(a)++ tmp.sort()++ # topological sort+ out = []+ while tmp:+ e = tmp.pop()+ if e in keys: out.append(e)+ try:+ nlst = prec[e]+ except KeyError:+ pass+ else:+ del prec[e]+ for x in nlst:+ for y in prec:+ if x in prec[y]:+ break+ else:+ tmp.append(x)++ if prec:+ raise Errors.WafError('Cycle detected in the method execution %r' % prec)+ out.reverse()+ self.meths = out++ # then we run the methods in order+ Logs.debug('task_gen: posting %s %d' % (self, id(self)))+ for x in out:+ try:+ v = getattr(self, x)+ except AttributeError:+ raise Errors.WafError('%r is not a valid task generator method' % x)+ Logs.debug('task_gen: -> %s (%d)' % (x, id(self)))+ v()++ Logs.debug('task_gen: posted %s' % self.name)+ return True++ def get_hook(self, node):+ """+ :param node: Input file to process+ :type node: :py:class:`waflib.Tools.Node.Node`+ :return: A method able to process the input node by looking at the extension+ :rtype: function+ """+ name = node.name+ for k in self.mappings:+ if name.endswith(k):+ return self.mappings[k]+ for k in task_gen.mappings:+ if name.endswith(k):+ return task_gen.mappings[k]+ raise Errors.WafError("File %r has no mapping in %r (did you forget to load a waf tool?)" % (node, task_gen.mappings.keys()))++ def create_task(self, name, src=None, tgt=None):+ """+ Wrapper for creating task instances. The classes are retrieved from the+ context class if possible, then from the global dict Task.classes.++ :param name: task class name+ :type name: string+ :param src: input nodes+ :type src: list of :py:class:`waflib.Tools.Node.Node`+ :param tgt: output nodes+ :type tgt: list of :py:class:`waflib.Tools.Node.Node`+ :return: A task object+ :rtype: :py:class:`waflib.Task.TaskBase`+ """+ task = Task.classes[name](env=self.env.derive(), generator=self)+ if src:+ task.set_inputs(src)+ if tgt:+ task.set_outputs(tgt)+ self.tasks.append(task)+ return task++ def clone(self, env):+ """+ Make a copy of a task generator. Once the copy is made, it is necessary to ensure that the+ it does not create the same output files as the original, or the same files may+ be compiled several times.++ :param env: A configuration set+ :type env: :py:class:`waflib.ConfigSet.ConfigSet`+ :return: A copy+ :rtype: :py:class:`waflib.TaskGen.task_gen`+ """+ newobj = self.bld()+ for x in self.__dict__:+ if x in ['env', 'bld']:+ continue+ elif x in ['path', 'features']:+ setattr(newobj, x, getattr(self, x))+ else:+ setattr(newobj, x, copy.copy(getattr(self, x)))++ newobj.posted = False+ if isinstance(env, str):+ newobj.env = self.bld.all_envs[env].derive()+ else:+ newobj.env = env.derive()++ return newobj++def declare_chain(name='', rule=None, reentrant=None, color='BLUE',+ ext_in=[], ext_out=[], before=[], after=[], decider=None, scan=None, install_path=None, shell=False):+ """+ Create a new mapping and a task class for processing files by extension.+ See Tools/flex.py for an example.++ :param name: name for the task class+ :type name: string+ :param rule: function to execute or string to be compiled in a function+ :type rule: string or function+ :param reentrant: re-inject the output file in the process (done automatically, set to 0 to disable)+ :type reentrant: int+ :param color: color for the task output+ :type color: string+ :param ext_in: execute the task only after the files of such extensions are created+ :type ext_in: list of string+ :param ext_out: execute the task only before files of such extensions are processed+ :type ext_out: list of string+ :param before: execute instances of this task before classes of the given names+ :type before: list of string+ :param after: execute instances of this task after classes of the given names+ :type after: list of string+ :param decider: if present, use it to create the output nodes for the task+ :type decider: function+ :param scan: scanner function for the task+ :type scan: function+ :param install_path: installation path for the output nodes+ :type install_path: string+ """+ ext_in = Utils.to_list(ext_in)+ ext_out = Utils.to_list(ext_out)+ if not name:+ name = rule+ cls = Task.task_factory(name, rule, color=color, ext_in=ext_in, ext_out=ext_out, before=before, after=after, scan=scan, shell=shell)++ def x_file(self, node):+ ext = decider and decider(self, node) or cls.ext_out+ if ext_in:+ _ext_in = ext_in[0]++ tsk = self.create_task(name, node)+ cnt = 0++ keys = list(self.mappings.keys()) + list(self.__class__.mappings.keys())+ for x in ext:+ k = node.change_ext(x, ext_in=_ext_in)+ tsk.outputs.append(k)++ if reentrant != None:+ if cnt < int(reentrant):+ self.source.append(k)+ else:+ for y in keys: # ~ nfile * nextensions :-/+ if k.name.endswith(y):+ self.source.append(k)+ break+ cnt += 1++ if install_path:+ self.bld.install_files(install_path, tsk.outputs)+ return tsk++ for x in cls.ext_in:+ task_gen.mappings[x] = x_file+ return x_file++def taskgen_method(func):+ """+ Decorator: register a method as a task generator method.+ The function must accept a task generator as first parameter::++ from waflib.TaskGen import taskgen_method+ @taskgen_method+ def mymethod(self):+ pass++ :param func: task generator method to add+ :type func: function+ :rtype: function+ """+ setattr(task_gen, func.__name__, func)+ return func++def feature(*k):+ """+ Decorator: register a task generator method that will be executed when the+ object attribute 'feature' contains the corresponding key(s)::++ from waflib.Task import feature+ @feature('myfeature')+ def myfunction(self):+ print('that is my feature!')+ def build(bld):+ bld(features='myfeature')++ :param k: feature names+ :type k: list of string+ """+ def deco(func):+ setattr(task_gen, func.__name__, func)+ for name in k:+ feats[name].update([func.__name__])+ return func+ return deco++def before_method(*k):+ """+ Decorator: register a task generator method which will be executed+ before the functions of given name(s)::++ from waflib.TaskGen import feature, before+ @feature('myfeature')+ @before_method('fun2')+ def fun1(self):+ print('feature 1!')+ @feature('myfeature')+ def fun2(self):+ print('feature 2!')+ def build(bld):+ bld(features='myfeature')++ :param k: method names+ :type k: list of string+ """+ def deco(func):+ setattr(task_gen, func.__name__, func)+ for fun_name in k:+ if not func.__name__ in task_gen.prec[fun_name]:+ task_gen.prec[fun_name].append(func.__name__)+ #task_gen.prec[fun_name].sort()+ return func+ return deco+before = before_method++def after_method(*k):+ """+ Decorator: register a task generator method which will be executed+ after the functions of given name(s)::++ from waflib.TaskGen import feature, after+ @feature('myfeature')+ @after_method('fun2')+ def fun1(self):+ print('feature 1!')+ @feature('myfeature')+ def fun2(self):+ print('feature 2!')+ def build(bld):+ bld(features='myfeature')++ :param k: method names+ :type k: list of string+ """+ def deco(func):+ setattr(task_gen, func.__name__, func)+ for fun_name in k:+ if not fun_name in task_gen.prec[func.__name__]:+ task_gen.prec[func.__name__].append(fun_name)+ #task_gen.prec[func.__name__].sort()+ return func+ return deco+after = after_method++def extension(*k):+ """+ Decorator: register a task generator method which will be invoked during+ the processing of source files for the extension given::++ from waflib import Task+ class mytask(Task):+ run_str = 'cp ${SRC} ${TGT}'+ @extension('.moo')+ def create_maa_file(self, node):+ self.create_task('mytask', node, node.change_ext('.maa'))+ def build(bld):+ bld(source='foo.moo')+ """+ def deco(func):+ setattr(task_gen, func.__name__, func)+ for x in k:+ task_gen.mappings[x] = func+ return func+ return deco++# ---------------------------------------------------------------+# The following methods are task generator methods commonly used+# they are almost examples, the rest of waf core does not depend on them++@taskgen_method+def to_nodes(self, lst, path=None):+ """+ Convert the input list into a list of nodes.+ It is used by :py:func:`waflib.TaskGen.process_source` and :py:func:`waflib.TaskGen.process_rule`.+ It is designed for source files, for folders, see :py:func:`waflib.Tools.ccroot.to_incnodes`:++ :param lst: input list+ :type lst: list of string and nodes+ :param path: path from which to search the nodes (by default, :py:attr:`waflib.TaskGen.task_gen.path`)+ :type path: :py:class:`waflib.Tools.Node.Node`+ :rtype: list of :py:class:`waflib.Tools.Node.Node`+ """+ tmp = []+ path = path or self.path+ find = path.find_resource++ if isinstance(lst, self.path.__class__):+ lst = [lst]++ # either a list or a string, convert to a list of nodes+ for x in Utils.to_list(lst):+ if isinstance(x, str):+ node = find(x)+ else:+ node = x+ if not node:+ raise Errors.WafError("source not found: %r in %r" % (x, self))+ tmp.append(node)+ return tmp++@feature('*')+def process_source(self):+ """+ Process each element in the attribute ``source`` by extension.++ #. The *source* list is converted through :py:meth:`waflib.TaskGen.to_nodes` to a list of :py:class:`waflib.Node.Node` first.+ #. File extensions are mapped to methods having the signature: ``def meth(self, node)`` by :py:meth:`waflib.TaskGen.extension`+ #. The method is retrieved through :py:meth:`waflib.TaskGen.task_gen.get_hook`+ #. When called, the methods may modify self.source to append more source to process+ #. The mappings can map an extension or a filename (see the code below)+ """+ self.source = self.to_nodes(getattr(self, 'source', []))+ for node in self.source:+ self.get_hook(node)(self, node)++@feature('*')+@before_method('process_source')+def process_rule(self):+ """+ Process the attribute ``rule``. When present, :py:meth:`waflib.TaskGen.process_source` is disabled::++ def build(bld):+ bld(rule='cp ${SRC} ${TGT}', source='wscript', target='bar.txt')+ """+ if not getattr(self, 'rule', None):+ return++ # create the task class+ name = str(getattr(self, 'name', None) or self.target or getattr(self.rule, '__name__', self.rule))++ # or we can put the class in a cache for performance reasons+ try:+ cache = self.bld.cache_rule_attr+ except AttributeError:+ cache = self.bld.cache_rule_attr = {}++ cls = None+ if getattr(self, 'cache_rule', 'True'):+ try:+ cls = cache[(name, self.rule)]+ except KeyError:+ pass+ if not cls:+ cls = Task.task_factory(name, self.rule,+ getattr(self, 'vars', []),+ shell=getattr(self, 'shell', True), color=getattr(self, 'color', 'BLUE'),+ scan = getattr(self, 'scan', None))+ if getattr(self, 'scan', None):+ cls.scan = self.scan+ elif getattr(self, 'deps', None):+ def scan(self):+ nodes = []+ for x in self.generator.to_list(getattr(self.generator, 'deps', None)):+ node = self.generator.path.find_resource(x)+ if not node:+ self.generator.bld.fatal('Could not find %r (was it declared?)' % x)+ nodes.append(node)+ return [nodes, []]+ cls.scan = scan++ if getattr(self, 'update_outputs', None):+ Task.update_outputs(cls)++ if getattr(self, 'always', None):+ Task.always_run(cls)++ for x in ['after', 'before', 'ext_in', 'ext_out']:+ setattr(cls, x, getattr(self, x, []))++ if getattr(self, 'cache_rule', 'True'):+ cache[(name, self.rule)] = cls++ # now create one instance+ tsk = self.create_task(name)++ if getattr(self, 'target', None):+ if isinstance(self.target, str):+ self.target = self.target.split()+ if not isinstance(self.target, list):+ self.target = [self.target]+ for x in self.target:+ if isinstance(x, str):+ tsk.outputs.append(self.path.find_or_declare(x))+ else:+ x.parent.mkdir() # if a node was given, create the required folders+ tsk.outputs.append(x)+ if getattr(self, 'install_path', None):+ # from waf 1.5+ # although convenient, it does not 1. allow to name the target file and 2. symlinks+ # TODO remove in waf 1.7+ self.bld.install_files(self.install_path, tsk.outputs)++ if getattr(self, 'source', None):+ tsk.inputs = self.to_nodes(self.source)+ # bypass the execution of process_source by setting the source to an empty list+ self.source = []++ if getattr(self, 'cwd', None):+ tsk.cwd = self.cwd++@feature('seq')+def sequence_order(self):+ """+ Add a strict sequential constraint between the tasks generated by task generators.+ It works because task generators are posted in order.+ It will not post objects which belong to other folders.++ Example::++ bld(features='javac seq')+ bld(features='jar seq')++ To start a new sequence, set the attribute seq_start, for example::++ obj = bld(features='seq')+ obj.seq_start = True++ Note that the method is executed in last position. This is more an+ example than a widely-used solution.+ """+ if self.meths and self.meths[-1] != 'sequence_order':+ self.meths.append('sequence_order')+ return++ if getattr(self, 'seq_start', None):+ return++ # all the tasks previously declared must be run before these+ if getattr(self.bld, 'prev', None):+ self.bld.prev.post()+ for x in self.bld.prev.tasks:+ for y in self.tasks:+ y.set_run_after(x)++ self.bld.prev = self+++re_m4 = re.compile('@(\w+)@', re.M)++class subst_pc(Task.Task):+ """+ Create *.pc* files from *.pc.in*. The task is executed whenever an input variable used+ in the substitution changes.+ """++ def run(self):+ "Substitutes variables in a .in file"++ if getattr(self.generator, 'is_copy', None):+ self.outputs[0].write(self.inputs[0].read('rb'), 'wb')+ if getattr(self.generator, 'chmod', None):+ os.chmod(self.outputs[0].abspath(), self.generator.chmod)+ return++ code = self.inputs[0].read(encoding=getattr(self.generator, 'encoding', 'ISO8859-1'))++ if getattr(self.generator, 'subst_fun', None):+ code = self.generator.subst_fun(self, code)+ if code:+ self.outputs[0].write(code, encoding=getattr(self.generator, 'encoding', 'ISO8859-1'))+ return++ # replace all % by %% to prevent errors by % signs+ code = code.replace('%', '%%')++ # extract the vars foo into lst and replace @foo@ by %(foo)s+ lst = []+ def repl(match):+ g = match.group+ if g(1):+ lst.append(g(1))+ return "%%(%s)s" % g(1)+ return ''+ code = re_m4.sub(repl, code)++ try:+ d = self.generator.dct+ except AttributeError:+ d = {}+ for x in lst:+ tmp = getattr(self.generator, x, '') or self.env.get_flat(x) or self.env.get_flat(x.upper())+ d[x] = str(tmp)++ code = code % d+ self.outputs[0].write(code, encoding=getattr(self.generator, 'encoding', 'ISO8859-1'))+ self.generator.bld.raw_deps[self.uid()] = self.dep_vars = lst++ # make sure the signature is updated+ try: delattr(self, 'cache_sig')+ except AttributeError: pass++ if getattr(self.generator, 'chmod', None):+ os.chmod(self.outputs[0].abspath(), self.generator.chmod)++ def sig_vars(self):+ """+ Compute a hash (signature) of the variables used in the substitution+ """+ bld = self.generator.bld+ env = self.env+ upd = self.m.update++ if getattr(self.generator, 'subst_fun', None):+ upd(Utils.h_fun(self.generator.subst_fun).encode())++ # raw_deps: persistent custom values returned by the scanner+ vars = self.generator.bld.raw_deps.get(self.uid(), [])++ # hash both env vars and task generator attributes+ act_sig = bld.hash_env_vars(env, vars)+ upd(act_sig)++ lst = [getattr(self.generator, x, '') for x in vars]+ upd(Utils.h_list(lst))++ return self.m.digest()++@extension('.pc.in')+def add_pcfile(self, node):+ """+ Process *.pc.in* files to *.pc*. Install the results to ``${PREFIX}/lib/pkgconfig/``++ def build(bld):+ bld(source='foo.pc.in', install_path='${LIBDIR}/pkgconfig/')+ """+ tsk = self.create_task('subst_pc', node, node.change_ext('.pc', '.pc.in'))+ self.bld.install_files(getattr(self, 'install_path', '${LIBDIR}/pkgconfig/'), tsk.outputs)++class subst(subst_pc):+ pass++@feature('subst')+@before_method('process_source', 'process_rule')+def process_subst(self):+ """+ Define a transformation that substitutes the contents of *source* files to *target* files::++ def build(bld):+ bld(+ features='subst',+ source='foo.c.in',+ target='foo.c',+ install_path='${LIBDIR}/pkgconfig',+ VAR = 'val'+ )++ The input files are supposed to contain macros of the form *@VAR@*, where *VAR* is an argument+ of the task generator object.++ This method overrides the processing by :py:meth:`waflib.TaskGen.process_source`.+ """++ src = Utils.to_list(getattr(self, 'source', []))+ if isinstance(src, Node.Node):+ src = [src]+ tgt = Utils.to_list(getattr(self, 'target', []))+ if isinstance(tgt, Node.Node):+ tgt = [tgt]+ if len(src) != len(tgt):+ raise Errors.WafError('invalid number of source/target for %r' % self)++ for x, y in zip(src, tgt):+ if not x or not y:+ raise Errors.WafError('null source or target for %r' % self)+ a, b = None, None++ if isinstance(x, str) and isinstance(y, str) and x == y:+ a = self.path.find_node(x)+ b = self.path.get_bld().make_node(y)+ if not os.path.isfile(b.abspath()):+ b.sig = None+ b.parent.mkdir()+ else:+ if isinstance(x, str):+ a = self.path.find_resource(x)+ elif isinstance(x, Node.Node):+ a = x+ if isinstance(y, str):+ b = self.path.find_or_declare(y)+ elif isinstance(y, Node.Node):+ b = y++ if not a:+ raise Errors.WafError('cound not find %r for %r' % (x, self))++ has_constraints = False+ tsk = self.create_task('subst', a, b)+ for k in ('after', 'before', 'ext_in', 'ext_out'):+ val = getattr(self, k, None)+ if val:+ has_constraints = True+ setattr(tsk, k, val)++ # paranoid safety measure for the general case foo.in->foo.h with ambiguous dependencies+ if not has_constraints and b.name.endswith('.h'):+ tsk.before = [k for k in ('c', 'cxx') if k in Task.classes]++ inst_to = getattr(self, 'install_path', None)+ if inst_to:+ self.bld.install_files(inst_to, b, chmod=getattr(self, 'chmod', Utils.O644))++ self.source = []+new file mode 100644@@ -0,0 +1,3 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)new file mode 100644@@ -0,0 +1,22 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)+# Ralf Habacker, 2006 (rh)++"""+The **ar** program creates static libraries. This tool is almost always loaded+from others (C, C++, D, etc) for static library support.+"""++from waflib.Configure import conf++@conf+def find_ar(conf):+ """Configuration helper used by C/C++ tools to enable the support for static libraries"""+ conf.load('ar')++def configure(conf):+ """Find the ar program and set the default flags in ``conf.env.ARFLAGS``"""+ conf.find_program('ar', var='AR')+ conf.env.ARFLAGS = 'rcs'+new file mode 100644@@ -0,0 +1,75 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2008-2010 (ita)++"""+Assembly support, used by tools such as gas and nasm++To declare targets using assembly::++ def configure(conf):+ conf.load('gcc gas')++ def build(bld):+ bld(+ features='c cstlib asm',+ source = 'test.S',+ target = 'asmtest')++ bld(+ features='asm asmprogram',+ source = 'test.S',+ target = 'asmtest')++Support for pure asm programs and libraries should also work::++ def configure(conf):+ conf.load('nasm')+ conf.find_program('ld', 'ASLINK')++ def build(bld):+ bld(+ features='asm asmprogram',+ source = 'test.S',+ target = 'asmtest')+"""++import os, sys+from waflib import Task, Utils+import waflib.Task+from waflib.Tools.ccroot import link_task, stlink_task+from waflib.TaskGen import extension, feature++class asm(Task.Task):+ """+ Compile asm files by gas/nasm/yasm/...+ """+ color = 'BLUE'+ run_str = '${AS} ${ASFLAGS} ${ASMPATH_ST:INCPATHS} ${AS_SRC_F}${SRC} ${AS_TGT_F}${TGT}'++@extension('.s', '.S', '.asm', '.ASM', '.spp', '.SPP')+def asm_hook(self, node):+ """+ Bind the asm extension to the asm task++ :param node: input file+ :type node: :py:class:`waflib.Node.Node`+ """+ return self.create_compiled_task('asm', node)++class asmprogram(link_task):+ "Link object files into a c program"+ run_str = '${ASLINK} ${ASLINKFLAGS} ${ASLNK_TGT_F}${TGT} ${ASLNK_SRC_F}${SRC}'+ ext_out = ['.bin']+ inst_to = '${BINDIR}'++class asmshlib(asmprogram):+ "Link object files into a c shared library"+ inst_to = '${LIBDIR}'++class asmstlib(stlink_task):+ "Link object files into a c static library"+ pass # do not remove++def configure(conf):+ conf.env['ASMPATH_ST'] = '-I%s'new file mode 100644@@ -0,0 +1,49 @@+#!/usr/bin/env python+# encoding: utf-8+# John O'Meara, 2006+# Thomas Nagy 2009-2010 (ita)++"""+The **bison** program is a code generator which creates C or C++ files.+The generated files are compiled into object files.+"""++from waflib import Task+from waflib.TaskGen import extension++class bison(Task.Task):+ """Compile bison files"""+ color = 'BLUE'+ run_str = '${BISON} ${BISONFLAGS} ${SRC[0].abspath()} -o ${TGT[0].name}'+ ext_out = ['.h'] # just to make sure++@extension('.y', '.yc', '.yy')+def big_bison(self, node):+ """+ Create a bison task, which must be executed from the directory of the output file.+ """+ has_h = '-d' in self.env['BISONFLAGS']++ outs = []+ if node.name.endswith('.yc'):+ outs.append(node.change_ext('.tab.cc'))+ if has_h:+ outs.append(node.change_ext('.tab.hh'))+ else:+ outs.append(node.change_ext('.tab.c'))+ if has_h:+ outs.append(node.change_ext('.tab.h'))++ tsk = self.create_task('bison', node, outs)+ tsk.cwd = node.parent.get_bld().abspath()++ # and the c/cxx file must be compiled too+ self.source.append(outs[0])++def configure(conf):+ """+ Detect the *bison* program+ """+ conf.find_program('bison', var='BISON')+ conf.env.BISONFLAGS = ['-d']+new file mode 100644@@ -0,0 +1,37 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"Base for c programs/libraries"++from waflib import TaskGen, Task, Utils+from waflib.Tools import c_preproc+from waflib.Tools.ccroot import link_task, stlink_task++@TaskGen.extension('.c')+def c_hook(self, node):+ "Bind the c file extension to the creation of a :py:class:`waflib.Tools.c.c` instance"+ return self.create_compiled_task('c', node)++class c(Task.Task):+ "Compile C files into object files"+ run_str = '${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT}'+ vars = ['CCDEPS'] # unused variable to depend on, just in case+ ext_in = ['.h'] # set the build order easily by using ext_out=['.h']+ scan = c_preproc.scan++class cprogram(link_task):+ "Link object files into a c program"+ run_str = '${LINK_CC} ${LINKFLAGS} ${CCLNK_SRC_F}${SRC} ${CCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB}'+ ext_out = ['.bin']+ vars = ['LINKDEPS']+ inst_to = '${BINDIR}'++class cshlib(cprogram):+ "Link object files into a c shared library"+ inst_to = '${LIBDIR}'++class cstlib(stlink_task):+ "Link object files into a c static library"+ pass # do not remove+new file mode 100644@@ -0,0 +1,128 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"base for all c/c++ programs and libraries"++import os, sys, re+from waflib import Utils, Build+from waflib.Configure import conf++def get_extensions(lst):+ """+ :param lst: files to process+ :list lst: list of string or :py:class:`waflib.Node.Node`+ :return: list of file extensions+ :rtype: list of string+ """+ ret = []+ for x in Utils.to_list(lst):+ try:+ if not isinstance(x, str):+ x = x.name+ ret.append(x[x.rfind('.') + 1:])+ except Exception:+ pass+ return ret++def sniff_features(**kw):+ """+ Look at the source files and return the features for a task generator (mainly cc and cxx)::++ snif_features(source=['foo.c', 'foo.cxx'], type='shlib')+ # returns ['cxx', 'c', 'cxxshlib', 'cshlib']++ :param source: source files to process+ :type source: list of string or :py:class:`waflib.Node.Node`+ :param type: object type in *program*, *shlib* or *stlib*+ :type type: string+ :return: the list of features for a task generator processing the source files+ :rtype: list of string+ """+ exts = get_extensions(kw['source'])+ type = kw['_type']+ feats = []++ # watch the order, cxx will have the precedence+ if 'cxx' in exts or 'cpp' in exts or 'c++' in exts or 'cc' in exts or 'C' in exts:+ feats.append('cxx')++ if 'c' in exts or 'vala' in exts:+ feats.append('c')++ if 'd' in exts:+ feats.append('d')++ if 'java' in exts:+ feats.append('java')++ if 'java' in exts:+ return 'java'++ if type in ['program', 'shlib', 'stlib']:+ for x in feats:+ if x in ['cxx', 'd', 'c']:+ feats.append(x + type)++ return feats++def set_features(kw, _type):+ kw['_type'] = _type+ kw['features'] = Utils.to_list(kw.get('features', [])) + Utils.to_list(sniff_features(**kw))++@conf+def program(bld, *k, **kw):+ """+ Alias for creating programs by looking at the file extensions::++ def build(bld):+ bld.program(source='foo.c', target='app')+ # equivalent to:+ # bld(features='c cprogram', source='foo.c', target='app')++ """+ set_features(kw, 'program')+ return bld(*k, **kw)++@conf+def shlib(bld, *k, **kw):+ """+ Alias for creating shared libraries by looking at the file extensions::++ def build(bld):+ bld.shlib(source='foo.c', target='app')+ # equivalent to:+ # bld(features='c cshlib', source='foo.c', target='app')++ """+ set_features(kw, 'shlib')+ return bld(*k, **kw)++@conf+def stlib(bld, *k, **kw):+ """+ Alias for creating static libraries by looking at the file extensions::++ def build(bld):+ bld.stlib(source='foo.cpp', target='app')+ # equivalent to:+ # bld(features='cxx cxxstlib', source='foo.cpp', target='app')++ """+ set_features(kw, 'stlib')+ return bld(*k, **kw)++@conf+def objects(bld, *k, **kw):+ """+ Alias for creating object files by looking at the file extensions::++ def build(bld):+ bld.objects(source='foo.c', target='app')+ # equivalent to:+ # bld(features='c', source='foo.c', target='app')++ """+ set_features(kw, 'objects')+ return bld(*k, **kw)+new file mode 100755@@ -0,0 +1,1234 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""+C/C++/D configuration helpers+"""++import os, re, shlex, sys+from waflib import Build, Utils, Task, Options, Logs, Errors, ConfigSet, Runner+from waflib.TaskGen import after_method, feature+from waflib.Configure import conf++WAF_CONFIG_H = 'config.h'+"""default name for the config.h file"""++DEFKEYS = 'define_key'+INCKEYS = 'include_key'++cfg_ver = {+ 'atleast-version': '>=',+ 'exact-version': '==',+ 'max-version': '<=',+}++SNIP_FUNCTION = '''+int main(int argc, char **argv) {+ (void)argc; (void)argv;+ void *p;+ p=(void*)(%s);+ return 0;+}+'''+"""Code template for checking for functions"""++SNIP_TYPE = '''+int main(int argc, char **argv) {+ (void)argc; (void)argv;+ if ((%(type_name)s *) 0) return 0;+ if (sizeof (%(type_name)s)) return 0;+ return 1;+}+'''+"""Code template for checking for types"""++SNIP_EMPTY_PROGRAM = '''+int main(int argc, char **argv) {+ (void)argc; (void)argv;+ return 0;+}+'''++SNIP_FIELD = '''+int main(int argc, char **argv) {+ (void)argc; (void)argv;+ char *off;+ off = (char*) &((%(type_name)s*)0)->%(field_name)s;+ return (size_t) off < sizeof(%(type_name)s);+}+'''++MACRO_TO_DESTOS = {+'__linux__' : 'linux',+'__GNU__' : 'gnu', # hurd+'__FreeBSD__' : 'freebsd',+'__NetBSD__' : 'netbsd',+'__OpenBSD__' : 'openbsd',+'__sun' : 'sunos',+'__hpux' : 'hpux',+'__sgi' : 'irix',+'_AIX' : 'aix',+'__CYGWIN__' : 'cygwin',+'__MSYS__' : 'msys',+'_UWIN' : 'uwin',+'_WIN64' : 'win32',+'_WIN32' : 'win32',+# Note about darwin: this is also tested with 'defined __APPLE__ && defined __MACH__' somewhere below in this file.+'__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' : 'darwin', +'__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' : 'darwin', # iphone+'__QNX__' : 'qnx',+'__native_client__' : 'nacl' # google native client platform+}++MACRO_TO_DEST_CPU = {+'__x86_64__' : 'x86_64',+'__amd64__' : 'x86_64',+'__i386__' : 'x86',+'__ia64__' : 'ia',+'__mips__' : 'mips',+'__sparc__' : 'sparc',+'__alpha__' : 'alpha',+'__aarch64__' : 'aarch64',+'__thumb__' : 'thumb',+'__arm__' : 'arm',+'__hppa__' : 'hppa',+'__powerpc__' : 'powerpc',+'__ppc__' : 'powerpc',+'__convex__' : 'convex',+'__m68k__' : 'm68k',+'__s390x__' : 's390x',+'__s390__' : 's390',+'__sh__' : 'sh',+}++@conf+def parse_flags(self, line, uselib_store, env=None, force_static=False):+ """+ Parse the flags from the input lines, and add them to the relevant use variables::++ def configure(conf):+ conf.parse_flags('-O3', 'FOO')+ # conf.env.CXXFLAGS_FOO = ['-O3']+ # conf.env.CFLAGS_FOO = ['-O3']++ :param line: flags+ :type line: string+ :param uselib_store: where to add the flags+ :type uselib_store: string+ :param env: config set or conf.env by default+ :type env: :py:class:`waflib.ConfigSet.ConfigSet`+ """++ assert(isinstance(line, str))++ env = env or self.env++ # append_unique is not always possible+ # for example, apple flags may require both -arch i386 and -arch ppc++ app = env.append_value+ appu = env.append_unique+ #lst = shlex.split(line)+ # issue #811+ lex = shlex.shlex(line, posix=False)+ lex.whitespace_split = True+ lex.commenters = ''+ lst = list(lex)++ uselib = uselib_store+ while lst:+ x = lst.pop(0)+ st = x[:2]+ ot = x[2:]++ if st == '-I' or st == '/I':+ if not ot: ot = lst.pop(0)+ appu('INCLUDES_' + uselib, [ot])+ elif st == '-include':+ tmp = [x, lst.pop(0)]+ app('CFLAGS', tmp)+ app('CXXFLAGS', tmp)+ elif st == '-D' or (env.CXX_NAME == 'msvc' and st == '/D'): # not perfect but..+ if not ot: ot = lst.pop(0)+ app('DEFINES_' + uselib, [ot])+ elif st == '-l':+ if not ot: ot = lst.pop(0)+ prefix = force_static and 'STLIB_' or 'LIB_'+ appu(prefix + uselib, [ot])+ elif st == '-L':+ if not ot: ot = lst.pop(0)+ appu('LIBPATH_' + uselib, [ot])+ elif x == '-pthread' or x.startswith('+') or x.startswith('-std'):+ app('CFLAGS_' + uselib, [x])+ app('CXXFLAGS_' + uselib, [x])+ app('LINKFLAGS_' + uselib, [x])+ elif x == '-framework':+ appu('FRAMEWORK_' + uselib, [lst.pop(0)])+ elif x.startswith('-F'):+ appu('FRAMEWORKPATH_' + uselib, [x[2:]])+ elif x.startswith('-Wl'):+ app('LINKFLAGS_' + uselib, [x])+ elif x.startswith('-m') or x.startswith('-f') or x.startswith('-dynamic'):+ app('CFLAGS_' + uselib, [x])+ app('CXXFLAGS_' + uselib, [x])+ elif x.startswith('-bundle'):+ app('LINKFLAGS_' + uselib, [x])+ elif x.startswith('-undefined'):+ arg = lst.pop(0)+ app('LINKFLAGS_' + uselib, [x, arg])+ elif x.startswith('-arch') or x.startswith('-isysroot'):+ tmp = [x, lst.pop(0)]+ app('CFLAGS_' + uselib, tmp)+ app('CXXFLAGS_' + uselib, tmp)+ app('LINKFLAGS_' + uselib, tmp)+ elif x.endswith('.a') or x.endswith('.so') or x.endswith('.dylib'):+ appu('LINKFLAGS_' + uselib, [x]) # not cool, #762++@conf+def ret_msg(self, f, kw):+ if isinstance(f, str):+ return f+ return f(kw)++@conf+def validate_cfg(self, kw):+ """+ Search for the program *pkg-config* if missing, and validate the parameters to pass to+ :py:func:`waflib.Tools.c_config.exec_cfg`.++ :param path: the **-config program to use** (default is *pkg-config*)+ :type path: list of string+ :param msg: message to display to describe the test executed+ :type msg: string+ :param okmsg: message to display when the test is successful+ :type okmsg: string+ :param errmsg: message to display in case of error+ :type errmsg: string+ """+ if not 'path' in kw:+ if not self.env.PKGCONFIG:+ self.find_program('pkg-config', var='PKGCONFIG')+ kw['path'] = self.env.PKGCONFIG++ # pkg-config version+ if 'atleast_pkgconfig_version' in kw:+ if not 'msg' in kw:+ kw['msg'] = 'Checking for pkg-config version >= %r' % kw['atleast_pkgconfig_version']+ return++ if not 'okmsg' in kw:+ kw['okmsg'] = 'yes'+ if not 'errmsg' in kw:+ kw['errmsg'] = 'not found'++ if 'modversion' in kw:+ if not 'msg' in kw:+ kw['msg'] = 'Checking for %r version' % kw['modversion']+ return++ # checking for the version of a module, for the moment, one thing at a time+ for x in cfg_ver.keys():+ y = x.replace('-', '_')+ if y in kw:+ if not 'package' in kw:+ raise ValueError('%s requires a package' % x)++ if not 'msg' in kw:+ kw['msg'] = 'Checking for %r %s %s' % (kw['package'], cfg_ver[x], kw[y])+ return++ if not 'msg' in kw:+ kw['msg'] = 'Checking for %r' % (kw['package'] or kw['path'])++@conf+def exec_cfg(self, kw):+ """+ Execute the program *pkg-config*:++ * if atleast_pkgconfig_version is given, check that pkg-config has the version n and return+ * if modversion is given, then return the module version+ * else, execute the *-config* program with the *args* and *variables* given, and set the flags on the *conf.env.FLAGS_name* variable++ :param atleast_pkgconfig_version: minimum pkg-config version to use (disable other tests)+ :type atleast_pkgconfig_version: string+ :param package: package name, for example *gtk+-2.0*+ :type package: string+ :param uselib_store: if the test is successful, define HAVE\_*name*. It is also used to define *conf.env.FLAGS_name* variables.+ :type uselib_store: string+ :param modversion: if provided, return the version of the given module and define *name*\_VERSION+ :type modversion: string+ :param args: arguments to give to *package* when retrieving flags+ :type args: list of string+ :param variables: return the values of particular variables+ :type variables: list of string+ :param define_variable: additional variables to define (also in conf.env.PKG_CONFIG_DEFINES)+ :type define_variable: dict(string: string)+ """++ def define_it():+ if kw.get('uselib_store', None):+ self.env.append_unique('DEFINES_%s' % kw['uselib_store'], "%s=1" % self.have_define(kw['uselib_store']))+ else:+ self.define(self.have_define(kw['package']), 1, 0)++ # pkg-config version+ if 'atleast_pkgconfig_version' in kw:+ cmd = [kw['path'], '--atleast-pkgconfig-version=%s' % kw['atleast_pkgconfig_version']]+ self.cmd_and_log(cmd)+ if not 'okmsg' in kw:+ kw['okmsg'] = 'yes'+ return++ # checking for the version of a module+ for x in cfg_ver:+ y = x.replace('-', '_')+ if y in kw:+ self.cmd_and_log([kw['path'], '--%s=%s' % (x, kw[y]), kw['package']])+ if not 'okmsg' in kw:+ kw['okmsg'] = 'yes'+ define_it()+ break++ # retrieving the version of a module+ if 'modversion' in kw:+ version = self.cmd_and_log([kw['path'], '--modversion', kw['modversion']]).strip()+ self.define('%s_VERSION' % Utils.quote_define_name(kw.get('uselib_store', kw['modversion'])), version)+ return version++ lst = [kw['path']]++ defi = kw.get('define_variable', None)+ if not defi:+ defi = self.env.PKG_CONFIG_DEFINES or {}+ for key, val in defi.items():+ lst.append('--define-variable=%s=%s' % (key, val))++ # retrieving variables of a module+ if 'variables' in kw:+ env = kw.get('env', self.env)+ uselib = kw.get('uselib_store', kw['package'].upper())+ vars = Utils.to_list(kw['variables'])+ for v in vars:+ val = self.cmd_and_log(lst + ['--variable=' + v]).strip()+ var = '%s_%s' % (uselib, v)+ env[var] = val+ if not 'okmsg' in kw:+ kw['okmsg'] = 'yes'+ return++ static = False+ if 'args' in kw:+ args = Utils.to_list(kw['args'])+ if '--static' in args or '--static-libs' in args:+ static = True+ lst += args++ # tools like pkgconf expect the package argument after the -- ones -_-+ lst.extend(Utils.to_list(kw['package']))++ # so we assume the command-line will output flags to be parsed afterwards+ ret = self.cmd_and_log(lst)+ if not 'okmsg' in kw:+ kw['okmsg'] = 'yes'++ define_it()+ self.parse_flags(ret, kw.get('uselib_store', kw['package'].upper()), kw.get('env', self.env), force_static=static)+ return ret++@conf+def check_cfg(self, *k, **kw):+ """+ Check for configuration flags using a **-config**-like program (pkg-config, sdl-config, etc).+ Encapsulate the calls to :py:func:`waflib.Tools.c_config.validate_cfg` and :py:func:`waflib.Tools.c_config.exec_cfg`++ A few examples::++ def configure(conf):+ conf.load('compiler_c')+ conf.check_cfg(package='glib-2.0', args='--libs --cflags')+ conf.check_cfg(package='glib-2.0', uselib_store='GLIB', atleast_version='2.10.0',+ args='--cflags --libs')+ conf.check_cfg(package='pango')+ conf.check_cfg(package='pango', uselib_store='MYPANGO', args=['--cflags', '--libs'])+ conf.check_cfg(package='pango',+ args=['pango >= 0.1.0', 'pango < 9.9.9', '--cflags', '--libs'],+ msg="Checking for 'pango 0.1.0'")+ conf.check_cfg(path='sdl-config', args='--cflags --libs', package='', uselib_store='SDL')+ conf.check_cfg(path='mpicc', args='--showme:compile --showme:link',+ package='', uselib_store='OPEN_MPI', mandatory=False)++ """+ if k:+ lst = k[0].split()+ kw['package'] = lst[0]+ kw['args'] = ' '.join(lst[1:])++ self.validate_cfg(kw)+ if 'msg' in kw:+ self.start_msg(kw['msg'])+ ret = None+ try:+ ret = self.exec_cfg(kw)+ except self.errors.WafError:+ if 'errmsg' in kw:+ self.end_msg(kw['errmsg'], 'YELLOW')+ if Logs.verbose > 1:+ raise+ else:+ self.fatal('The configuration failed')+ else:+ kw['success'] = ret+ if 'okmsg' in kw:+ self.end_msg(self.ret_msg(kw['okmsg'], kw))++ return ret++@conf+def validate_c(self, kw):+ """+ pre-check the parameters that will be given to run_c_code++ :param compiler: c or cxx (tries to guess what is best)+ :type compiler: string+ :param type: cprogram, cshlib, cstlib - not required if *features are given directly*+ :type type: binary to create+ :param feature: desired features for the task generator that will execute the test, for example ``cxx cxxstlib``+ :type feature: list of string+ :param fragment: provide a piece of code for the test (default is to let the system create one)+ :type fragment: string+ :param uselib_store: define variables after the test is executed (IMPORTANT!)+ :type uselib_store: string+ :param use: parameters to use for building (just like the normal *use* keyword)+ :type use: list of string+ :param define_name: define to set when the check is over+ :type define_name: string+ :param execute: execute the resulting binary+ :type execute: bool+ :param define_ret: if execute is set to True, use the execution output in both the define and the return value+ :type define_ret: bool+ :param header_name: check for a particular header+ :type header_name: string+ :param auto_add_header_name: if header_name was set, add the headers in env.INCKEYS so the next tests will include these headers+ :type auto_add_header_name: bool+ """++ if not 'env' in kw:+ kw['env'] = self.env.derive()+ env = kw['env']++ if not 'compiler' in kw and not 'features' in kw:+ kw['compiler'] = 'c'+ if env['CXX_NAME'] and Task.classes.get('cxx', None):+ kw['compiler'] = 'cxx'+ if not self.env['CXX']:+ self.fatal('a c++ compiler is required')+ else:+ if not self.env['CC']:+ self.fatal('a c compiler is required')++ if not 'compile_mode' in kw:+ kw['compile_mode'] = 'c'+ if 'cxx' in Utils.to_list(kw.get('features',[])) or kw.get('compiler', '') == 'cxx':+ kw['compile_mode'] = 'cxx'++ if not 'type' in kw:+ kw['type'] = 'cprogram'++ if not 'features' in kw:+ kw['features'] = [kw['compile_mode'], kw['type']] # "cprogram c"+ else:+ kw['features'] = Utils.to_list(kw['features'])++ if not 'compile_filename' in kw:+ kw['compile_filename'] = 'test.c' + ((kw['compile_mode'] == 'cxx') and 'pp' or '')+++ def to_header(dct):+ if 'header_name' in dct:+ dct = Utils.to_list(dct['header_name'])+ return ''.join(['#include <%s>\n' % x for x in dct])+ return ''++ #OSX+ if 'framework_name' in kw:+ fwkname = kw['framework_name']+ if not 'uselib_store' in kw:+ kw['uselib_store'] = fwkname.upper()++ if not kw.get('no_header', False):+ if not 'header_name' in kw:+ kw['header_name'] = []+ fwk = '%s/%s.h' % (fwkname, fwkname)+ if kw.get('remove_dot_h', None):+ fwk = fwk[:-2]+ kw['header_name'] = Utils.to_list(kw['header_name']) + [fwk]++ kw['msg'] = 'Checking for framework %s' % fwkname+ kw['framework'] = fwkname+ #kw['frameworkpath'] = set it yourself++ if 'function_name' in kw:+ fu = kw['function_name']+ if not 'msg' in kw:+ kw['msg'] = 'Checking for function %s' % fu+ kw['code'] = to_header(kw) + SNIP_FUNCTION % fu+ if not 'uselib_store' in kw:+ kw['uselib_store'] = fu.upper()+ if not 'define_name' in kw:+ kw['define_name'] = self.have_define(fu)++ elif 'type_name' in kw:+ tu = kw['type_name']+ if not 'header_name' in kw:+ kw['header_name'] = 'stdint.h'+ if 'field_name' in kw:+ field = kw['field_name']+ kw['code'] = to_header(kw) + SNIP_FIELD % {'type_name' : tu, 'field_name' : field}+ if not 'msg' in kw:+ kw['msg'] = 'Checking for field %s in %s' % (field, tu)+ if not 'define_name' in kw:+ kw['define_name'] = self.have_define((tu + '_' + field).upper())+ else:+ kw['code'] = to_header(kw) + SNIP_TYPE % {'type_name' : tu}+ if not 'msg' in kw:+ kw['msg'] = 'Checking for type %s' % tu+ if not 'define_name' in kw:+ kw['define_name'] = self.have_define(tu.upper())++ elif 'header_name' in kw:+ if not 'msg' in kw:+ kw['msg'] = 'Checking for header %s' % kw['header_name']++ l = Utils.to_list(kw['header_name'])+ assert len(l)>0, 'list of headers in header_name is empty'++ kw['code'] = to_header(kw) + SNIP_EMPTY_PROGRAM++ if not 'uselib_store' in kw:+ kw['uselib_store'] = l[0].upper()++ if not 'define_name' in kw:+ kw['define_name'] = self.have_define(l[0])++ if 'lib' in kw:+ if not 'msg' in kw:+ kw['msg'] = 'Checking for library %s' % kw['lib']+ if not 'uselib_store' in kw:+ kw['uselib_store'] = kw['lib'].upper()++ if 'stlib' in kw:+ if not 'msg' in kw:+ kw['msg'] = 'Checking for static library %s' % kw['stlib']+ if not 'uselib_store' in kw:+ kw['uselib_store'] = kw['stlib'].upper()++ if 'fragment' in kw:+ # an additional code fragment may be provided to replace the predefined code+ # in custom headers+ kw['code'] = kw['fragment']+ if not 'msg' in kw:+ kw['msg'] = 'Checking for code snippet'+ if not 'errmsg' in kw:+ kw['errmsg'] = 'no'++ for (flagsname,flagstype) in [('cxxflags','compiler'), ('cflags','compiler'), ('linkflags','linker')]:+ if flagsname in kw:+ if not 'msg' in kw:+ kw['msg'] = 'Checking for %s flags %s' % (flagstype, kw[flagsname])+ if not 'errmsg' in kw:+ kw['errmsg'] = 'no'++ if not 'execute' in kw:+ kw['execute'] = False+ if kw['execute']:+ kw['features'].append('test_exec')++ if not 'errmsg' in kw:+ kw['errmsg'] = 'not found'++ if not 'okmsg' in kw:+ kw['okmsg'] = 'yes'++ if not 'code' in kw:+ kw['code'] = SNIP_EMPTY_PROGRAM++ # if there are headers to append automatically to the next tests+ if self.env[INCKEYS]:+ kw['code'] = '\n'.join(['#include <%s>' % x for x in self.env[INCKEYS]]) + '\n' + kw['code']++ if not kw.get('success'): kw['success'] = None++ if 'define_name' in kw:+ self.undefine(kw['define_name'])++ assert 'msg' in kw, 'invalid parameters, read http://freehackers.org/~tnagy/wafbook/single.html#config_helpers_c'++@conf+def post_check(self, *k, **kw):+ "Set the variables after a test executed in :py:func:`waflib.Tools.c_config.check` was run successfully"++ is_success = 0+ if kw['execute']:+ if kw['success'] is not None:+ if kw.get('define_ret', False):+ is_success = kw['success']+ else:+ is_success = (kw['success'] == 0)+ else:+ is_success = (kw['success'] == 0)++ if 'define_name' in kw:+ # TODO simplify?+ if 'header_name' in kw or 'function_name' in kw or 'type_name' in kw or 'fragment' in kw:+ if kw['execute'] and kw.get('define_ret', None) and isinstance(is_success, str):+ self.define(kw['define_name'], is_success, quote=kw.get('quote', 1))+ else:+ self.define_cond(kw['define_name'], is_success)+ else:+ self.define_cond(kw['define_name'], is_success)++ if 'header_name' in kw:+ if kw.get('auto_add_header_name', False):+ self.env.append_value(INCKEYS, Utils.to_list(kw['header_name']))++ if is_success and 'uselib_store' in kw:+ from waflib.Tools import ccroot++ # TODO see get_uselib_vars from ccroot.py+ _vars = set([])+ for x in kw['features']:+ if x in ccroot.USELIB_VARS:+ _vars |= ccroot.USELIB_VARS[x]++ for k in _vars:+ lk = k.lower()+ if k == 'INCLUDES': lk = 'includes'+ if k == 'DEFINES': lk = 'defines'+ if lk in kw:+ val = kw[lk]+ # remove trailing slash+ if isinstance(val, str):+ val = val.rstrip(os.path.sep)+ self.env.append_unique(k + '_' + kw['uselib_store'], val)+ return is_success++@conf+def check(self, *k, **kw):+ """+ Perform a configuration test by calling :py:func:`waflib.Tools.c_config.run_c_code`.+ For the complete list of parameters, see :py:func:`waflib.Tools.c_config.validate_c`.+ To force a specific compiler, prefer the methods :py:func:`waflib.Tools.c_config.check_cxx` or :py:func:`waflib.Tools.c_config.check_cc`+ """+ self.validate_c(kw)+ self.start_msg(kw['msg'])+ ret = None+ try:+ ret = self.run_c_code(*k, **kw)+ except self.errors.ConfigurationError:+ self.end_msg(kw['errmsg'], 'YELLOW')+ if Logs.verbose > 1:+ raise+ else:+ self.fatal('The configuration failed')+ else:+ kw['success'] = ret++ ret = self.post_check(*k, **kw)+ if not ret:+ self.end_msg(kw['errmsg'], 'YELLOW')+ self.fatal('The configuration failed %r' % ret)+ else:+ self.end_msg(self.ret_msg(kw['okmsg'], kw))+ return ret++class test_exec(Task.Task):+ """+ A task for executing a programs after they are built. See :py:func:`waflib.Tools.c_config.test_exec_fun`.+ """+ color = 'PINK'+ def run(self):+ if getattr(self.generator, 'rpath', None):+ if getattr(self.generator, 'define_ret', False):+ self.generator.bld.retval = self.generator.bld.cmd_and_log([self.inputs[0].abspath()])+ else:+ self.generator.bld.retval = self.generator.bld.exec_command([self.inputs[0].abspath()])+ else:+ env = self.env.env or {}+ env.update(dict(os.environ))+ for var in ('LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'PATH'):+ env[var] = self.inputs[0].parent.abspath() + os.path.pathsep + env.get(var, '')+ if getattr(self.generator, 'define_ret', False):+ self.generator.bld.retval = self.generator.bld.cmd_and_log([self.inputs[0].abspath()], env=env)+ else:+ self.generator.bld.retval = self.generator.bld.exec_command([self.inputs[0].abspath()], env=env)++@feature('test_exec')+@after_method('apply_link')+def test_exec_fun(self):+ """+ The feature **test_exec** is used to create a task that will to execute the binary+ created (link task output) during the build. The exit status will be set+ on the build context, so only one program may have the feature *test_exec*.+ This is used by configuration tests::++ def configure(conf):+ conf.check(execute=True)+ """+ self.create_task('test_exec', self.link_task.outputs[0])++CACHE_RESULTS = 1+COMPILE_ERRORS = 2++@conf+def run_c_code(self, *k, **kw):+ """+ Create a temporary build context to execute a build. A reference to that build+ context is kept on self.test_bld for debugging purposes, and you should not rely+ on it too much (read the note on the cache below).+ The parameters given in the arguments to this function are passed as arguments for+ a single task generator created in the build. Only three parameters are obligatory:++ :param features: features to pass to a task generator created in the build+ :type features: list of string+ :param compile_filename: file to create for the compilation (default: *test.c*)+ :type compile_filename: string+ :param code: code to write in the filename to compile+ :type code: string++ Though this function returns *0* by default, the build may set an attribute named *retval* on the+ build context object to return a particular value. See :py:func:`waflib.Tools.c_config.test_exec_fun` for example.++ This function also provides a limited cache. To use it, provide the following option::++ def options(opt):+ opt.add_option('--confcache', dest='confcache', default=0,+ action='count', help='Use a configuration cache')++ And execute the configuration with the following command-line::++ $ waf configure --confcache++ """++ lst = [str(v) for (p, v) in kw.items() if p != 'env']+ h = Utils.h_list(lst)+ dir = self.bldnode.abspath() + os.sep + (not Utils.is_win32 and '.' or '') + 'conf_check_' + Utils.to_hex(h)++ try:+ os.makedirs(dir)+ except OSError:+ pass++ try:+ os.stat(dir)+ except OSError:+ self.fatal('cannot use the configuration test folder %r' % dir)++ cachemode = getattr(Options.options, 'confcache', None)+ if cachemode == CACHE_RESULTS:+ try:+ proj = ConfigSet.ConfigSet(os.path.join(dir, 'cache_run_c_code'))+ except OSError:+ pass+ else:+ ret = proj['cache_run_c_code']+ if isinstance(ret, str) and ret.startswith('Test does not build'):+ self.fatal(ret)+ return ret++ bdir = os.path.join(dir, 'testbuild')++ if not os.path.exists(bdir):+ os.makedirs(bdir)++ self.test_bld = bld = Build.BuildContext(top_dir=dir, out_dir=bdir)+ bld.init_dirs()+ bld.progress_bar = 0+ bld.targets = '*'++ if kw['compile_filename']:+ node = bld.srcnode.make_node(kw['compile_filename'])+ node.write(kw['code'])++ bld.logger = self.logger+ bld.all_envs.update(self.all_envs) # not really necessary+ bld.env = kw['env']++ o = bld(features=kw['features'], source=kw['compile_filename'], target='testprog')++ for k, v in kw.items():+ setattr(o, k, v)++ self.to_log("==>\n%s\n<==" % kw['code'])++ # compile the program+ bld.targets = '*'++ ret = -1+ try:+ try:+ bld.compile()+ except Errors.WafError:+ ret = 'Test does not build: %s' % Utils.ex_stack()+ self.fatal(ret)+ else:+ ret = getattr(bld, 'retval', 0)+ finally:+ # cache the results each time+ proj = ConfigSet.ConfigSet()+ proj['cache_run_c_code'] = ret+ proj.store(os.path.join(dir, 'cache_run_c_code'))++ return ret++@conf+def check_cxx(self, *k, **kw):+ """+ Same as :py:func:`waflib.Tools.c_config.check` but default to the *c++* programming language+ """+ kw['compiler'] = 'cxx'+ return self.check(*k, **kw)++@conf+def check_cc(self, *k, **kw):+ """+ Same as :py:func:`waflib.Tools.c_config.check` but default to the *c* programming language+ """+ kw['compiler'] = 'c'+ return self.check(*k, **kw)++@conf+def define(self, key, val, quote=True):+ """+ Store a single define and its state into conf.env.DEFINES. If the value is True, False or None it is cast to 1 or 0.++ :param key: define name+ :type key: string+ :param val: value+ :type val: int or string+ :param quote: enclose strings in quotes (yes by default)+ :type quote: bool+ """+ assert key and isinstance(key, str)++ if val is True:+ val = 1+ elif val in (False, None):+ val = 0++ if isinstance(val, int) or isinstance(val, float):+ s = '%s=%s'+ else:+ s = quote and '%s="%s"' or '%s=%s'+ app = s % (key, str(val))++ ban = key + '='+ lst = self.env['DEFINES']+ for x in lst:+ if x.startswith(ban):+ lst[lst.index(x)] = app+ break+ else:+ self.env.append_value('DEFINES', app)++ self.env.append_unique(DEFKEYS, key)++@conf+def undefine(self, key):+ """+ Remove a define from conf.env.DEFINES++ :param key: define name+ :type key: string+ """+ assert key and isinstance(key, str)++ ban = key + '='+ lst = [x for x in self.env['DEFINES'] if not x.startswith(ban)]+ self.env['DEFINES'] = lst+ self.env.append_unique(DEFKEYS, key)++@conf+def define_cond(self, key, val):+ """+ Conditionally define a name::++ def configure(conf):+ conf.define_cond('A', True)+ # equivalent to:+ # if val: conf.define('A', 1)+ # else: conf.undefine('A')++ :param key: define name+ :type key: string+ :param val: value+ :type val: int or string+ """+ assert key and isinstance(key, str)++ if val:+ self.define(key, 1)+ else:+ self.undefine(key)++@conf+def is_defined(self, key):+ """+ :param key: define name+ :type key: string+ :return: True if the define is set+ :rtype: bool+ """+ assert key and isinstance(key, str)++ ban = key + '='+ for x in self.env['DEFINES']:+ if x.startswith(ban):+ return True+ return False++@conf+def get_define(self, key):+ """+ :param key: define name+ :type key: string+ :return: the value of a previously stored define or None if it is not set+ """+ assert key and isinstance(key, str)++ ban = key + '='+ for x in self.env['DEFINES']:+ if x.startswith(ban):+ return x[len(ban):]+ return None++@conf+def have_define(self, key):+ """+ :param key: define name+ :type key: string+ :return: the input key prefixed by *HAVE_* and substitute any invalid characters.+ :rtype: string+ """+ return (self.env.HAVE_PAT or 'HAVE_%s') % Utils.quote_define_name(key)++@conf+def write_config_header(self, configfile='', guard='', top=False, env=None, defines=True, headers=False, remove=True, define_prefix=''):+ """+ Write a configuration header containing defines and includes::++ def configure(cnf):+ cnf.define('A', 1)+ cnf.write_config_header('config.h')++ :param configfile: relative path to the file to create+ :type configfile: string+ :param guard: include guard name to add, by default it is computed from the file name+ :type guard: string+ :param top: write the configuration header from the build directory (default is from the current path)+ :type top: bool+ :param defines: add the defines (yes by default)+ :type defines: bool+ :param headers: add #include in the file+ :type headers: bool+ :param remove: remove the defines after they are added (yes by default, works like in autoconf)+ :type remove: bool+ :type define_prefix: string+ :param define_prefix: prefix all the defines in the file with a particular prefix+ """+ # TODO waf 1.8: the parameter env is not used+ if env:+ Logs.warn('Cannot pass env to write_config_header')++ if not configfile: configfile = WAF_CONFIG_H+ waf_guard = guard or 'W_%s_WAF' % Utils.quote_define_name(configfile)++ node = top and self.bldnode or self.path.get_bld()+ node = node.make_node(configfile)+ node.parent.mkdir()++ lst = ['/* WARNING! All changes made to this file will be lost! */\n']+ lst.append('#ifndef %s\n#define %s\n' % (waf_guard, waf_guard))+ lst.append(self.get_config_header(defines, headers, define_prefix=define_prefix))+ lst.append('\n#endif /* %s */\n' % waf_guard)++ node.write('\n'.join(lst))++ # config files are not removed on "waf clean"+ self.env.append_unique(Build.CFG_FILES, [node.abspath()])++ if remove:+ for key in self.env[DEFKEYS]:+ self.undefine(key)+ self.env[DEFKEYS] = []++@conf+def get_config_header(self, defines=True, headers=False, define_prefix=''):+ """+ Create the contents of a ``config.h`` file from the defines and includes+ set in conf.env.define_key / conf.env.include_key. No include guards are added.++ :param defines: write the defines values+ :type defines: bool+ :param headers: write the headers+ :type headers: bool+ :type define_prefix: string+ :param define_prefix: prefix all the defines with a particular prefix+ :return: the contents of a ``config.h`` file+ :rtype: string+ """+ lst = []+ if headers:+ for x in self.env[INCKEYS]:+ lst.append('#include <%s>' % x)++ if defines:+ for x in self.env[DEFKEYS]:+ if self.is_defined(x):+ val = self.get_define(x)+ lst.append('#define %s %s' % (define_prefix + x, val))+ else:+ lst.append('/* #undef %s */' % (define_prefix + x))+ return "\n".join(lst)++@conf+def cc_add_flags(conf):+ """+ Read the CFLAGS/CPPFLAGS from os.environ and add to conf.env.CFLAGS+ """+ conf.add_os_flags('CPPFLAGS', 'CFLAGS')+ conf.add_os_flags('CFLAGS')++@conf+def cxx_add_flags(conf):+ """+ Read the CXXFLAGS/CPPFLAGS and add to conf.env.CXXFLAGS+ """+ conf.add_os_flags('CPPFLAGS', 'CXXFLAGS')+ conf.add_os_flags('CXXFLAGS')++@conf+def link_add_flags(conf):+ """+ Read the LINKFLAGS/LDFLAGS and add to conf.env.LDFLAGS+ """+ conf.add_os_flags('LINKFLAGS')+ conf.add_os_flags('LDFLAGS', 'LINKFLAGS')++@conf+def cc_load_tools(conf):+ """+ Load the c tool+ """+ if not conf.env.DEST_OS:+ conf.env.DEST_OS = Utils.unversioned_sys_platform()+ conf.load('c')++@conf+def cxx_load_tools(conf):+ """+ Load the cxx tool+ """+ if not conf.env.DEST_OS:+ conf.env.DEST_OS = Utils.unversioned_sys_platform()+ conf.load('cxx')++@conf+def get_cc_version(conf, cc, gcc=False, icc=False):+ """+ Run the preprocessor to determine the compiler version++ The variables CC_VERSION, DEST_OS, DEST_BINFMT and DEST_CPU will be set in *conf.env*+ """+ cmd = cc + ['-dM', '-E', '-']+ env = conf.env.env or None+ try:+ p = Utils.subprocess.Popen(cmd, stdin=Utils.subprocess.PIPE, stdout=Utils.subprocess.PIPE, stderr=Utils.subprocess.PIPE, env=env)+ p.stdin.write('\n'.encode())+ out = p.communicate()[0]+ except Exception:+ conf.fatal('Could not determine the compiler version %r' % cmd)++ if not isinstance(out, str):+ out = out.decode(sys.stdout.encoding or 'iso8859-1')++ if gcc:+ if out.find('__INTEL_COMPILER') >= 0:+ conf.fatal('The intel compiler pretends to be gcc')+ if out.find('__GNUC__') < 0:+ conf.fatal('Could not determine the compiler type')++ if icc and out.find('__INTEL_COMPILER') < 0:+ conf.fatal('Not icc/icpc')++ k = {}+ if icc or gcc:+ out = out.splitlines()+ for line in out:+ lst = shlex.split(line)+ if len(lst)>2:+ key = lst[1]+ val = lst[2]+ k[key] = val++ def isD(var):+ return var in k++ def isT(var):+ return var in k and k[var] != '0'++ # Some documentation is available at http://predef.sourceforge.net+ # The names given to DEST_OS must match what Utils.unversioned_sys_platform() returns.+ if not conf.env.DEST_OS:+ conf.env.DEST_OS = ''+ for i in MACRO_TO_DESTOS:+ if isD(i):+ conf.env.DEST_OS = MACRO_TO_DESTOS[i]+ break+ else:+ if isD('__APPLE__') and isD('__MACH__'):+ conf.env.DEST_OS = 'darwin'+ elif isD('__unix__'): # unix must be tested last as it's a generic fallback+ conf.env.DEST_OS = 'generic'++ if isD('__ELF__'):+ conf.env.DEST_BINFMT = 'elf'+ elif isD('__WINNT__') or isD('__CYGWIN__'):+ conf.env.DEST_BINFMT = 'pe'+ conf.env.LIBDIR = conf.env['PREFIX'] + '/bin'+ elif isD('__APPLE__'):+ conf.env.DEST_BINFMT = 'mac-o'++ if not conf.env.DEST_BINFMT:+ # Infer the binary format from the os name.+ conf.env.DEST_BINFMT = Utils.destos_to_binfmt(conf.env.DEST_OS)++ for i in MACRO_TO_DEST_CPU:+ if isD(i):+ conf.env.DEST_CPU = MACRO_TO_DEST_CPU[i]+ break++ Logs.debug('ccroot: dest platform: ' + ' '.join([conf.env[x] or '?' for x in ('DEST_OS', 'DEST_BINFMT', 'DEST_CPU')]))+ if icc:+ ver = k['__INTEL_COMPILER']+ conf.env['CC_VERSION'] = (ver[:-2], ver[-2], ver[-1])+ else:+ if isD('__clang__'):+ conf.env['CC_VERSION'] = (k['__clang_major__'], k['__clang_minor__'], k['__clang_patchlevel__'])+ else:+ conf.env['CC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__'])+ return k++@conf+def get_xlc_version(conf, cc):+ """Get the compiler version"""++ cmd = cc + ['-qversion']+ try:+ out, err = conf.cmd_and_log(cmd, output=0)+ except Errors.WafError:+ conf.fatal('Could not find xlc %r' % cmd)++ # the intention is to catch the 8.0 in "IBM XL C/C++ Enterprise Edition V8.0 for AIX..."+ for v in (r"IBM XL C/C\+\+.* V(?P<major>\d*)\.(?P<minor>\d*)"):+ version_re = re.compile(v, re.I).search+ match = version_re(out or err)+ if match:+ k = match.groupdict()+ conf.env['CC_VERSION'] = (k['major'], k['minor'])+ break+ else:+ conf.fatal('Could not determine the XLC version.')++# ============ the --as-needed flag should added during the configuration, not at runtime =========++@conf+def add_as_needed(self):+ """+ Add ``--as-needed`` to the *LINKFLAGS*+ """+ if self.env.DEST_BINFMT == 'elf' and 'gcc' in (self.env.CXX_NAME, self.env.CC_NAME):+ self.env.append_unique('LINKFLAGS', '--as-needed')++# ============ parallel configuration++class cfgtask(Task.TaskBase):+ """+ A task that executes configuration tests+ make sure that the checks write to conf.env in a thread-safe manner++ for the moment it only executes conf.check+ """+ def display(self):+ return ''++ def runnable_status(self):+ return Task.RUN_ME++ def uid(self):+ return Utils.SIG_NIL++ def run(self):+ conf = self.conf+ bld = Build.BuildContext(top_dir=conf.srcnode.abspath(), out_dir=conf.bldnode.abspath())+ bld.env = conf.env+ bld.init_dirs()+ bld.in_msg = 1 # suppress top-level start_msg+ bld.logger = self.logger+ try:+ bld.check(**self.args)+ except Exception:+ return 1++@conf+def multicheck(self, *k, **kw):+ """+ Use tuples to perform parallel configuration tests+ """+ self.start_msg(kw.get('msg', 'Executing %d configuration tests' % len(k)))++ class par(object):+ def __init__(self):+ self.keep = False+ self.cache_global = Options.cache_global+ self.nocache = Options.options.nocache+ self.returned_tasks = []+ self.task_sigs = {}+ def total(self):+ return len(tasks)+ def to_log(self, *k, **kw):+ return++ bld = par()+ tasks = []+ for dct in k:+ x = cfgtask(bld=bld)+ tasks.append(x)+ x.args = dct+ x.bld = bld+ x.conf = self+ x.args = dct++ # bind a logger that will keep the info in memory+ x.logger = Logs.make_mem_logger(str(id(x)), self.logger)++ def it():+ yield tasks+ while 1:+ yield []+ p = Runner.Parallel(bld, Options.options.jobs)+ p.biter = it()+ p.start()++ # flush the logs in order into the config.log+ for x in tasks:+ x.logger.memhandler.flush()++ for x in tasks:+ if x.hasrun != Task.SUCCESS:+ self.end_msg(kw.get('errmsg', 'no'), color='YELLOW')+ self.fatal(kw.get('fatalmsg', None) or 'One of the tests has failed, see the config.log for more information')++ self.end_msg('ok')+new file mode 100644@@ -0,0 +1,188 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy 2008-2010++"""+MacOSX related tools+"""++import os, shutil, sys, platform+from waflib import TaskGen, Task, Build, Options, Utils, Errors+from waflib.TaskGen import taskgen_method, feature, after_method, before_method++app_info = '''+<?xml version="1.0" encoding="UTF-8"?>+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">+<plist version="0.9">+<dict>+ <key>CFBundlePackageType</key>+ <string>APPL</string>+ <key>CFBundleGetInfoString</key>+ <string>Created by Waf</string>+ <key>CFBundleSignature</key>+ <string>????</string>+ <key>NOTE</key>+ <string>THIS IS A GENERATED FILE, DO NOT MODIFY</string>+ <key>CFBundleExecutable</key>+ <string>%s</string>+</dict>+</plist>+'''+"""+plist template+"""++@feature('c', 'cxx')+def set_macosx_deployment_target(self):+ """+ see WAF issue 285 and also and also http://trac.macports.org/ticket/17059+ """+ if self.env['MACOSX_DEPLOYMENT_TARGET']:+ os.environ['MACOSX_DEPLOYMENT_TARGET'] = self.env['MACOSX_DEPLOYMENT_TARGET']+ elif 'MACOSX_DEPLOYMENT_TARGET' not in os.environ:+ if Utils.unversioned_sys_platform() == 'darwin':+ os.environ['MACOSX_DEPLOYMENT_TARGET'] = '.'.join(platform.mac_ver()[0].split('.')[:2])++@taskgen_method+def create_bundle_dirs(self, name, out):+ """+ Create bundle folders, used by :py:func:`create_task_macplist` and :py:func:`create_task_macapp`+ """+ bld = self.bld+ dir = out.parent.find_or_declare(name)+ dir.mkdir()+ macos = dir.find_or_declare(['Contents', 'MacOS'])+ macos.mkdir()+ return dir++def bundle_name_for_output(out):+ name = out.name+ k = name.rfind('.')+ if k >= 0:+ name = name[:k] + '.app'+ else:+ name = name + '.app'+ return name++@feature('cprogram', 'cxxprogram')+@after_method('apply_link')+def create_task_macapp(self):+ """+ To compile an executable into a Mac application (a .app), set its *mac_app* attribute::++ def build(bld):+ bld.shlib(source='a.c', target='foo', mac_app = True)++ To force *all* executables to be transformed into Mac applications::++ def build(bld):+ bld.env.MACAPP = True+ bld.shlib(source='a.c', target='foo')+ """+ if self.env['MACAPP'] or getattr(self, 'mac_app', False):+ out = self.link_task.outputs[0]++ name = bundle_name_for_output(out)+ dir = self.create_bundle_dirs(name, out)++ n1 = dir.find_or_declare(['Contents', 'MacOS', out.name])++ self.apptask = self.create_task('macapp', self.link_task.outputs, n1)+ inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Contents/MacOS/' % name+ self.bld.install_files(inst_to, n1, chmod=Utils.O755)++ if getattr(self, 'mac_resources', None):+ res_dir = n1.parent.parent.make_node('Resources')+ inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Resources' % name+ for x in self.to_list(self.mac_resources):+ node = self.path.find_node(x)+ if not node:+ raise Errors.WafError('Missing mac_resource %r in %r' % (x, self))++ parent = node.parent+ if os.path.isdir(node.abspath()):+ nodes = node.ant_glob('**')+ else:+ nodes = [node]+ for node in nodes:+ rel = node.path_from(parent)+ tsk = self.create_task('macapp', node, res_dir.make_node(rel))+ self.bld.install_as(inst_to + '/%s' % rel, node)++ if getattr(self.bld, 'is_install', None):+ # disable the normal binary installation+ self.install_task.hasrun = Task.SKIP_ME++@feature('cprogram', 'cxxprogram')+@after_method('apply_link')+def create_task_macplist(self):+ """+ Create a :py:class:`waflib.Tools.c_osx.macplist` instance.+ """+ if self.env['MACAPP'] or getattr(self, 'mac_app', False):+ out = self.link_task.outputs[0]++ name = bundle_name_for_output(out)++ dir = self.create_bundle_dirs(name, out)+ n1 = dir.find_or_declare(['Contents', 'Info.plist'])+ self.plisttask = plisttask = self.create_task('macplist', [], n1)++ if getattr(self, 'mac_plist', False):+ node = self.path.find_resource(self.mac_plist)+ if node:+ plisttask.inputs.append(node)+ else:+ plisttask.code = self.mac_plist+ else:+ plisttask.code = app_info % self.link_task.outputs[0].name++ inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Contents/' % name+ self.bld.install_files(inst_to, n1)++@feature('cshlib', 'cxxshlib')+@before_method('apply_link', 'propagate_uselib_vars')+def apply_bundle(self):+ """+ To make a bundled shared library (a ``.bundle``), set the *mac_bundle* attribute::++ def build(bld):+ bld.shlib(source='a.c', target='foo', mac_bundle = True)++ To force *all* executables to be transformed into bundles::++ def build(bld):+ bld.env.MACBUNDLE = True+ bld.shlib(source='a.c', target='foo')+ """+ if self.env['MACBUNDLE'] or getattr(self, 'mac_bundle', False):+ self.env['LINKFLAGS_cshlib'] = self.env['LINKFLAGS_cxxshlib'] = [] # disable the '-dynamiclib' flag+ self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['macbundle_PATTERN']+ use = self.use = self.to_list(getattr(self, 'use', []))+ if not 'MACBUNDLE' in use:+ use.append('MACBUNDLE')++app_dirs = ['Contents', 'Contents/MacOS', 'Contents/Resources']++class macapp(Task.Task):+ """+ Create mac applications+ """+ color = 'PINK'+ def run(self):+ self.outputs[0].parent.mkdir()+ shutil.copy2(self.inputs[0].srcpath(), self.outputs[0].abspath())++class macplist(Task.Task):+ """+ Create plist files+ """+ color = 'PINK'+ ext_in = ['.bin']+ def run(self):+ if getattr(self, 'code', None):+ txt = self.code+ else:+ txt = self.inputs[0].read()+ self.outputs[0].write(txt)+new file mode 100644@@ -0,0 +1,1031 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+C/C++ preprocessor for finding dependencies++Reasons for using the Waf preprocessor by default++#. Some c/c++ extensions (Qt) require a custom preprocessor for obtaining the dependencies (.moc files)+#. Not all compilers provide .d files for obtaining the dependencies (portability)+#. A naive file scanner will not catch the constructs such as "#include foo()"+#. A naive file scanner will catch unnecessary dependencies (change an unused header -> recompile everything)++Regarding the speed concerns:++* the preprocessing is performed only when files must be compiled+* the macros are evaluated only for #if/#elif/#include+* system headers are not scanned by default++Now if you do not want the Waf preprocessor, the tool +gccdeps* uses the .d files produced+during the compilation to track the dependencies (useful when used with the boost libraries).+It only works with gcc >= 4.4 though.++A dumb preprocessor is also available in the tool *c_dumbpreproc*+"""+# TODO: more varargs, pragma once++import re, string, traceback+from waflib import Logs, Utils, Errors+from waflib.Logs import debug, error++class PreprocError(Errors.WafError):+ pass++POPFILE = '-'+"Constant representing a special token used in :py:meth:`waflib.Tools.c_preproc.c_parser.start` iteration to switch to a header read previously"++recursion_limit = 150+"Limit on the amount of files to read in the dependency scanner"++go_absolute = False+"Set to True to track headers on files in /usr/include, else absolute paths are ignored (but it becomes very slow)"++standard_includes = ['/usr/include']+if Utils.is_win32:+ standard_includes = []++use_trigraphs = 0+"""Apply trigraph rules (False by default)"""++strict_quotes = 0+"""Reserve the "#include <>" quotes for system includes (do not search for those includes). False by default."""++g_optrans = {+'not':'!',+'and':'&&',+'bitand':'&',+'and_eq':'&=',+'or':'||',+'bitor':'|',+'or_eq':'|=',+'xor':'^',+'xor_eq':'^=',+'compl':'~',+}+"""Operators such as and/or/xor for c++. Set an empty dict to disable."""++# ignore #warning and #error+re_lines = re.compile(+ '^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*)\r*$',+ re.IGNORECASE | re.MULTILINE)+"""Match #include lines"""++re_mac = re.compile("^[a-zA-Z_]\w*")+"""Match macro definitions"""++re_fun = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*[(]')+"""Match macro functions"""++re_pragma_once = re.compile('^\s*once\s*', re.IGNORECASE)+"""Match #pragma once statements"""++re_nl = re.compile('\\\\\r*\n', re.MULTILINE)+"""Match newlines"""++re_cpp = re.compile(+ r"""(/\*[^*]*\*+([^/*][^*]*\*+)*/)|//[^\n]*|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)""",+ re.MULTILINE)+"""Filter C/C++ comments"""++trig_def = [('??'+a, b) for a, b in zip("=-/!'()<>", r'#~\|^[]{}')]+"""Trigraph definitions"""++chr_esc = {'0':0, 'a':7, 'b':8, 't':9, 'n':10, 'f':11, 'v':12, 'r':13, '\\':92, "'":39}+"""Escape characters"""++NUM = 'i'+"""Number token"""++OP = 'O'+"""Operator token"""++IDENT = 'T'+"""Identifier token"""++STR = 's'+"""String token"""++CHAR = 'c'+"""Character token"""++tok_types = [NUM, STR, IDENT, OP]+"""Token types"""++exp_types = [+ r"""0[xX](?P<hex>[a-fA-F0-9]+)(?P<qual1>[uUlL]*)|L*?'(?P<char>(\\.|[^\\'])+)'|(?P<n1>\d+)[Ee](?P<exp0>[+-]*?\d+)(?P<float0>[fFlL]*)|(?P<n2>\d*\.\d+)([Ee](?P<exp1>[+-]*?\d+))?(?P<float1>[fFlL]*)|(?P<n4>\d+\.\d*)([Ee](?P<exp2>[+-]*?\d+))?(?P<float2>[fFlL]*)|(?P<oct>0*)(?P<n0>\d+)(?P<qual2>[uUlL]*)""",+ r'L?"([^"\\]|\\.)*"',+ r'[a-zA-Z_]\w*',+ r'%:%:|<<=|>>=|\.\.\.|<<|<%|<:|<=|>>|>=|\+\+|\+=|--|->|-=|\*=|/=|%:|%=|%>|==|&&|&=|\|\||\|=|\^=|:>|!=|##|[\(\)\{\}\[\]<>\?\|\^\*\+&=:!#;,%/\-\?\~\.]',+]+"""Expression types"""++re_clexer = re.compile('|'.join(["(?P<%s>%s)" % (name, part) for name, part in zip(tok_types, exp_types)]), re.M)+"""Match expressions into tokens"""++accepted = 'a'+"""Parser state is *accepted*"""++ignored = 'i'+"""Parser state is *ignored*, for example preprocessor lines in an #if 0 block"""++undefined = 'u'+"""Parser state is *undefined* at the moment"""++skipped = 's'+"""Parser state is *skipped*, for example preprocessor lines in a #elif 0 block"""++def repl(m):+ """Replace function used with :py:attr:`waflib.Tools.c_preproc.re_cpp`"""+ s = m.group(1)+ if s:+ return ' '+ return m.group(3) or ''++def filter_comments(filename):+ """+ Filter the comments from a c/h file, and return the preprocessor lines.+ The regexps :py:attr:`waflib.Tools.c_preproc.re_cpp`, :py:attr:`waflib.Tools.c_preproc.re_nl` and :py:attr:`waflib.Tools.c_preproc.re_lines` are used internally.++ :return: the preprocessor directives as a list of (keyword, line)+ :rtype: a list of string pairs+ """+ # return a list of tuples : keyword, line+ code = Utils.readf(filename)+ if use_trigraphs:+ for (a, b) in trig_def: code = code.split(a).join(b)+ code = re_nl.sub('', code)+ code = re_cpp.sub(repl, code)+ return [(m.group(2), m.group(3)) for m in re.finditer(re_lines, code)]++prec = {}+"""+Operator precendence rules required for parsing expressions of the form::++ #if 1 && 2 != 0+"""+ops = ['* / %', '+ -', '<< >>', '< <= >= >', '== !=', '& | ^', '&& ||', ',']+for x in range(len(ops)):+ syms = ops[x]+ for u in syms.split():+ prec[u] = x++def trimquotes(s):+ """+ Remove the single quotes around an expression::++ trimquotes("'test'") == "test"++ :param s: expression to transform+ :type s: string+ :rtype: string+ """+ if not s: return ''+ s = s.rstrip()+ if s[0] == "'" and s[-1] == "'": return s[1:-1]+ return s++def reduce_nums(val_1, val_2, val_op):+ """+ Apply arithmetic rules to compute a result++ :param val1: input parameter+ :type val1: int or string+ :param val2: input parameter+ :type val2: int or string+ :param val_op: C operator in *+*, */*, *-*, etc+ :type val_op: string+ :rtype: int+ """+ #print val_1, val_2, val_op++ # now perform the operation, make certain a and b are numeric+ try: a = 0 + val_1+ except TypeError: a = int(val_1)+ try: b = 0 + val_2+ except TypeError: b = int(val_2)++ d = val_op+ if d == '%': c = a%b+ elif d=='+': c = a+b+ elif d=='-': c = a-b+ elif d=='*': c = a*b+ elif d=='/': c = a/b+ elif d=='^': c = a^b+ elif d=='|': c = a|b+ elif d=='||': c = int(a or b)+ elif d=='&': c = a&b+ elif d=='&&': c = int(a and b)+ elif d=='==': c = int(a == b)+ elif d=='!=': c = int(a != b)+ elif d=='<=': c = int(a <= b)+ elif d=='<': c = int(a < b)+ elif d=='>': c = int(a > b)+ elif d=='>=': c = int(a >= b)+ elif d=='^': c = int(a^b)+ elif d=='<<': c = a<<b+ elif d=='>>': c = a>>b+ else: c = 0+ return c++def get_num(lst):+ """+ Try to obtain a number from a list of tokens. The token types are defined in :py:attr:`waflib.Tools.ccroot.tok_types`.++ :param lst: list of preprocessor tokens+ :type lst: list of tuple (tokentype, value)+ :return: a pair containing the number and the rest of the list+ :rtype: tuple(value, list)+ """+ if not lst: raise PreprocError("empty list for get_num")+ (p, v) = lst[0]+ if p == OP:+ if v == '(':+ count_par = 1+ i = 1+ while i < len(lst):+ (p, v) = lst[i]++ if p == OP:+ if v == ')':+ count_par -= 1+ if count_par == 0:+ break+ elif v == '(':+ count_par += 1+ i += 1+ else:+ raise PreprocError("rparen expected %r" % lst)++ (num, _) = get_term(lst[1:i])+ return (num, lst[i+1:])++ elif v == '+':+ return get_num(lst[1:])+ elif v == '-':+ num, lst = get_num(lst[1:])+ return (reduce_nums('-1', num, '*'), lst)+ elif v == '!':+ num, lst = get_num(lst[1:])+ return (int(not int(num)), lst)+ elif v == '~':+ num, lst = get_num(lst[1:])+ return (~ int(num), lst)+ else:+ raise PreprocError("Invalid op token %r for get_num" % lst)+ elif p == NUM:+ return v, lst[1:]+ elif p == IDENT:+ # all macros should have been replaced, remaining identifiers eval to 0+ return 0, lst[1:]+ else:+ raise PreprocError("Invalid token %r for get_num" % lst)++def get_term(lst):+ """+ Evaluate an expression recursively, for example::++ 1+1+1 -> 2+1 -> 3++ :param lst: list of tokens+ :type lst: list of tuple(token, value)+ :return: the value and the remaining tokens+ :rtype: value, list+ """++ if not lst: raise PreprocError("empty list for get_term")+ num, lst = get_num(lst)+ if not lst:+ return (num, [])+ (p, v) = lst[0]+ if p == OP:+ if v == ',':+ # skip+ return get_term(lst[1:])+ elif v == '?':+ count_par = 0+ i = 1+ while i < len(lst):+ (p, v) = lst[i]++ if p == OP:+ if v == ')':+ count_par -= 1+ elif v == '(':+ count_par += 1+ elif v == ':':+ if count_par == 0:+ break+ i += 1+ else:+ raise PreprocError("rparen expected %r" % lst)++ if int(num):+ return get_term(lst[1:i])+ else:+ return get_term(lst[i+1:])++ else:+ num2, lst = get_num(lst[1:])++ if not lst:+ # no more tokens to process+ num2 = reduce_nums(num, num2, v)+ return get_term([(NUM, num2)] + lst)++ # operator precedence+ p2, v2 = lst[0]+ if p2 != OP:+ raise PreprocError("op expected %r" % lst)++ if prec[v2] >= prec[v]:+ num2 = reduce_nums(num, num2, v)+ return get_term([(NUM, num2)] + lst)+ else:+ num3, lst = get_num(lst[1:])+ num3 = reduce_nums(num2, num3, v2)+ return get_term([(NUM, num), (p, v), (NUM, num3)] + lst)+++ raise PreprocError("cannot reduce %r" % lst)++def reduce_eval(lst):+ """+ Take a list of tokens and output true or false for #if/#elif conditions.++ :param lst: a list of tokens+ :type lst: list of tuple(token, value)+ :return: a token+ :rtype: tuple(NUM, int)+ """+ num, lst = get_term(lst)+ return (NUM, num)++def stringize(lst):+ """+ Merge a list of tokens into a string++ :param lst: a list of tokens+ :type lst: list of tuple(token, value)+ :rtype: string+ """+ lst = [str(v2) for (p2, v2) in lst]+ return "".join(lst)++def paste_tokens(t1, t2):+ """+ Token pasting works between identifiers, particular operators, and identifiers and numbers::++ a ## b -> ab+ > ## = -> >=+ a ## 2 -> a2++ :param t1: token+ :type t1: tuple(type, value)+ :param t2: token+ :type t2: tuple(type, value)+ """+ p1 = None+ if t1[0] == OP and t2[0] == OP:+ p1 = OP+ elif t1[0] == IDENT and (t2[0] == IDENT or t2[0] == NUM):+ p1 = IDENT+ elif t1[0] == NUM and t2[0] == NUM:+ p1 = NUM+ if not p1:+ raise PreprocError('tokens do not make a valid paste %r and %r' % (t1, t2))+ return (p1, t1[1] + t2[1])++def reduce_tokens(lst, defs, ban=[]):+ """+ Replace the tokens in lst, using the macros provided in defs, and a list of macros that cannot be re-applied++ :param lst: list of tokens+ :type lst: list of tuple(token, value)+ :param defs: macro definitions+ :type defs: dict+ :param ban: macros that cannot be substituted (recursion is not allowed)+ :type ban: list of string+ :return: the new list of tokens+ :rtype: value, list+ """+ i = 0++ while i < len(lst):+ (p, v) = lst[i]++ if p == IDENT and v == "defined":+ del lst[i]+ if i < len(lst):+ (p2, v2) = lst[i]+ if p2 == IDENT:+ if v2 in defs:+ lst[i] = (NUM, 1)+ else:+ lst[i] = (NUM, 0)+ elif p2 == OP and v2 == '(':+ del lst[i]+ (p2, v2) = lst[i]+ del lst[i] # remove the ident, and change the ) for the value+ if v2 in defs:+ lst[i] = (NUM, 1)+ else:+ lst[i] = (NUM, 0)+ else:+ raise PreprocError("Invalid define expression %r" % lst)++ elif p == IDENT and v in defs:++ if isinstance(defs[v], str):+ a, b = extract_macro(defs[v])+ defs[v] = b+ macro_def = defs[v]+ to_add = macro_def[1]++ if isinstance(macro_def[0], list):+ # macro without arguments+ del lst[i]+ accu = to_add[:]+ reduce_tokens(accu, defs, ban+[v])+ for x in range(len(accu)):+ lst.insert(i, accu[x])+ i += 1+ else:+ # collect the arguments for the funcall++ args = []+ del lst[i]++ if i >= len(lst):+ raise PreprocError("expected '(' after %r (got nothing)" % v)++ (p2, v2) = lst[i]+ if p2 != OP or v2 != '(':+ raise PreprocError("expected '(' after %r" % v)++ del lst[i]++ one_param = []+ count_paren = 0+ while i < len(lst):+ p2, v2 = lst[i]++ del lst[i]+ if p2 == OP and count_paren == 0:+ if v2 == '(':+ one_param.append((p2, v2))+ count_paren += 1+ elif v2 == ')':+ if one_param: args.append(one_param)+ break+ elif v2 == ',':+ if not one_param: raise PreprocError("empty param in funcall %s" % p)+ args.append(one_param)+ one_param = []+ else:+ one_param.append((p2, v2))+ else:+ one_param.append((p2, v2))+ if v2 == '(': count_paren += 1+ elif v2 == ')': count_paren -= 1+ else:+ raise PreprocError('malformed macro')++ # substitute the arguments within the define expression+ accu = []+ arg_table = macro_def[0]+ j = 0+ while j < len(to_add):+ (p2, v2) = to_add[j]++ if p2 == OP and v2 == '#':+ # stringize is for arguments only+ if j+1 < len(to_add) and to_add[j+1][0] == IDENT and to_add[j+1][1] in arg_table:+ toks = args[arg_table[to_add[j+1][1]]]+ accu.append((STR, stringize(toks)))+ j += 1+ else:+ accu.append((p2, v2))+ elif p2 == OP and v2 == '##':+ # token pasting, how can man invent such a complicated system?+ if accu and j+1 < len(to_add):+ # we have at least two tokens++ t1 = accu[-1]++ if to_add[j+1][0] == IDENT and to_add[j+1][1] in arg_table:+ toks = args[arg_table[to_add[j+1][1]]]++ if toks:+ accu[-1] = paste_tokens(t1, toks[0]) #(IDENT, accu[-1][1] + toks[0][1])+ accu.extend(toks[1:])+ else:+ # error, case "a##"+ accu.append((p2, v2))+ accu.extend(toks)+ elif to_add[j+1][0] == IDENT and to_add[j+1][1] == '__VA_ARGS__':+ # TODO not sure+ # first collect the tokens+ va_toks = []+ st = len(macro_def[0])+ pt = len(args)+ for x in args[pt-st+1:]:+ va_toks.extend(x)+ va_toks.append((OP, ','))+ if va_toks: va_toks.pop() # extra comma+ if len(accu)>1:+ (p3, v3) = accu[-1]+ (p4, v4) = accu[-2]+ if v3 == '##':+ # remove the token paste+ accu.pop()+ if v4 == ',' and pt < st:+ # remove the comma+ accu.pop()+ accu += va_toks+ else:+ accu[-1] = paste_tokens(t1, to_add[j+1])++ j += 1+ else:+ # Invalid paste, case "##a" or "b##"+ accu.append((p2, v2))++ elif p2 == IDENT and v2 in arg_table:+ toks = args[arg_table[v2]]+ reduce_tokens(toks, defs, ban+[v])+ accu.extend(toks)+ else:+ accu.append((p2, v2))++ j += 1+++ reduce_tokens(accu, defs, ban+[v])++ for x in range(len(accu)-1, -1, -1):+ lst.insert(i, accu[x])++ i += 1+++def eval_macro(lst, defs):+ """+ Reduce the tokens by :py:func:`waflib.Tools.c_preproc.reduce_tokens` and try to return a 0/1 result by :py:func:`waflib.Tools.c_preproc.reduce_eval`.++ :param lst: list of tokens+ :type lst: list of tuple(token, value)+ :param defs: macro definitions+ :type defs: dict+ :rtype: int+ """+ reduce_tokens(lst, defs, [])+ if not lst: raise PreprocError("missing tokens to evaluate")+ (p, v) = reduce_eval(lst)+ return int(v) != 0++def extract_macro(txt):+ """+ Process a macro definition of the form::+ #define f(x, y) x * y++ into a function or a simple macro without arguments++ :param txt: expression to exact a macro definition from+ :type txt: string+ :return: a tuple containing the name, the list of arguments and the replacement+ :rtype: tuple(string, [list, list])+ """+ t = tokenize(txt)+ if re_fun.search(txt):+ p, name = t[0]++ p, v = t[1]+ if p != OP: raise PreprocError("expected open parenthesis")++ i = 1+ pindex = 0+ params = {}+ prev = '('++ while 1:+ i += 1+ p, v = t[i]++ if prev == '(':+ if p == IDENT:+ params[v] = pindex+ pindex += 1+ prev = p+ elif p == OP and v == ')':+ break+ else:+ raise PreprocError("unexpected token (3)")+ elif prev == IDENT:+ if p == OP and v == ',':+ prev = v+ elif p == OP and v == ')':+ break+ else:+ raise PreprocError("comma or ... expected")+ elif prev == ',':+ if p == IDENT:+ params[v] = pindex+ pindex += 1+ prev = p+ elif p == OP and v == '...':+ raise PreprocError("not implemented (1)")+ else:+ raise PreprocError("comma or ... expected (2)")+ elif prev == '...':+ raise PreprocError("not implemented (2)")+ else:+ raise PreprocError("unexpected else")++ #~ print (name, [params, t[i+1:]])+ return (name, [params, t[i+1:]])+ else:+ (p, v) = t[0]+ return (v, [[], t[1:]])++re_include = re.compile('^\s*(<(?P<a>.*)>|"(?P<b>.*)")')+def extract_include(txt, defs):+ """+ Process a line in the form::++ #include foo++ :param txt: include line to process+ :type txt: string+ :param defs: macro definitions+ :type defs: dict+ :return: the file name+ :rtype: string+ """+ m = re_include.search(txt)+ if m:+ if m.group('a'): return '<', m.group('a')+ if m.group('b'): return '"', m.group('b')++ # perform preprocessing and look at the result, it must match an include+ toks = tokenize(txt)+ reduce_tokens(toks, defs, ['waf_include'])++ if not toks:+ raise PreprocError("could not parse include %s" % txt)++ if len(toks) == 1:+ if toks[0][0] == STR:+ return '"', toks[0][1]+ else:+ if toks[0][1] == '<' and toks[-1][1] == '>':+ return stringize(toks).lstrip('<').rstrip('>')++ raise PreprocError("could not parse include %s." % txt)++def parse_char(txt):+ """+ Parse a c character++ :param txt: character to parse+ :type txt: string+ :return: a character literal+ :rtype: string+ """++ if not txt: raise PreprocError("attempted to parse a null char")+ if txt[0] != '\\':+ return ord(txt)+ c = txt[1]+ if c == 'x':+ if len(txt) == 4 and txt[3] in string.hexdigits: return int(txt[2:], 16)+ return int(txt[2:], 16)+ elif c.isdigit():+ if c == '0' and len(txt)==2: return 0+ for i in 3, 2, 1:+ if len(txt) > i and txt[1:1+i].isdigit():+ return (1+i, int(txt[1:1+i], 8))+ else:+ try: return chr_esc[c]+ except KeyError: raise PreprocError("could not parse char literal '%s'" % txt)++def tokenize(s):+ """+ Convert a string into a list of tokens (shlex.split does not apply to c/c++/d)++ :param s: input to tokenize+ :type s: string+ :return: a list of tokens+ :rtype: list of tuple(token, value)+ """+ return tokenize_private(s)[:] # force a copy of the results++@Utils.run_once+def tokenize_private(s):+ ret = []+ for match in re_clexer.finditer(s):+ m = match.group+ for name in tok_types:+ v = m(name)+ if v:+ if name == IDENT:+ try: v = g_optrans[v]; name = OP+ except KeyError:+ # c++ specific+ if v.lower() == "true":+ v = 1+ name = NUM+ elif v.lower() == "false":+ v = 0+ name = NUM+ elif name == NUM:+ if m('oct'): v = int(v, 8)+ elif m('hex'): v = int(m('hex'), 16)+ elif m('n0'): v = m('n0')+ else:+ v = m('char')+ if v: v = parse_char(v)+ else: v = m('n2') or m('n4')+ elif name == OP:+ if v == '%:': v = '#'+ elif v == '%:%:': v = '##'+ elif name == STR:+ # remove the quotes around the string+ v = v[1:-1]+ ret.append((name, v))+ break+ return ret++@Utils.run_once+def define_name(line):+ """+ :param line: define line+ :type line: string+ :rtype: string+ :return: the define name+ """+ return re_mac.match(line).group(0)++class c_parser(object):+ """+ Used by :py:func:`waflib.Tools.c_preproc.scan` to parse c/h files. Note that by default,+ only project headers are parsed.+ """+ def __init__(self, nodepaths=None, defines=None):+ self.lines = []+ """list of lines read"""++ if defines is None:+ self.defs = {}+ else:+ self.defs = dict(defines) # make a copy+ self.state = []++ self.count_files = 0+ self.currentnode_stack = []++ self.nodepaths = nodepaths or []+ """Include paths"""++ self.nodes = []+ """List of :py:class:`waflib.Node.Node` found so far"""++ self.names = []+ """List of file names that could not be matched by any file"""++ self.curfile = ''+ """Current file"""++ self.ban_includes = set([])+ """Includes that must not be read (#pragma once)"""++ def cached_find_resource(self, node, filename):+ """+ Find a file from the input directory++ :param node: directory+ :type node: :py:class:`waflib.Node.Node`+ :param filename: header to find+ :type filename: string+ :return: the node if found, or None+ :rtype: :py:class:`waflib.Node.Node`+ """+ try:+ nd = node.ctx.cache_nd+ except AttributeError:+ nd = node.ctx.cache_nd = {}++ tup = (node, filename)+ try:+ return nd[tup]+ except KeyError:+ ret = node.find_resource(filename)+ if ret:+ if getattr(ret, 'children', None):+ ret = None+ elif ret.is_child_of(node.ctx.bldnode):+ tmp = node.ctx.srcnode.search_node(ret.path_from(node.ctx.bldnode))+ if tmp and getattr(tmp, 'children', None):+ ret = None+ nd[tup] = ret+ return ret++ def tryfind(self, filename):+ """+ Try to obtain a node from the filename based from the include paths. Will add+ the node found to :py:attr:`waflib.Tools.c_preproc.c_parser.nodes` or the file name to+ :py:attr:`waflib.Tools.c_preproc.c_parser.names` if no corresponding file is found. Called by+ :py:attr:`waflib.Tools.c_preproc.c_parser.start`.++ :param filename: header to find+ :type filename: string+ :return: the node if found+ :rtype: :py:class:`waflib.Node.Node`+ """+ self.curfile = filename++ # for msvc it should be a for loop on the whole stack+ found = self.cached_find_resource(self.currentnode_stack[-1], filename)++ for n in self.nodepaths:+ if found:+ break+ found = self.cached_find_resource(n, filename)++ if found:+ # TODO the duplicates do not increase the no-op build times too much, but they may be worth removing+ self.nodes.append(found)+ if filename[-4:] != '.moc':+ self.addlines(found)+ else:+ if not filename in self.names:+ self.names.append(filename)+ return found++ def addlines(self, node):+ """+ Add the lines from a header in the list of preprocessor lines to parse++ :param node: header+ :type node: :py:class:`waflib.Node.Node`+ """++ self.currentnode_stack.append(node.parent)+ filepath = node.abspath()++ self.count_files += 1+ if self.count_files > recursion_limit:+ # issue #812+ raise PreprocError("recursion limit exceeded")+ pc = self.parse_cache+ debug('preproc: reading file %r', filepath)+ try:+ lns = pc[filepath]+ except KeyError:+ pass+ else:+ self.lines.extend(lns)+ return++ try:+ lines = filter_comments(filepath)+ lines.append((POPFILE, ''))+ lines.reverse()+ pc[filepath] = lines # cache the lines filtered+ self.lines.extend(lines)+ except IOError:+ raise PreprocError("could not read the file %s" % filepath)+ except Exception:+ if Logs.verbose > 0:+ error("parsing %s failed" % filepath)+ traceback.print_exc()++ def start(self, node, env):+ """+ Preprocess a source file to obtain the dependencies, which are accumulated to :py:attr:`waflib.Tools.c_preproc.c_parser.nodes`+ and :py:attr:`waflib.Tools.c_preproc.c_parser.names`.++ :param node: source file+ :type node: :py:class:`waflib.Node.Node`+ :param env: config set containing additional defines to take into account+ :type env: :py:class:`waflib.ConfigSet.ConfigSet`+ """++ debug('preproc: scanning %s (in %s)', node.name, node.parent.name)++ bld = node.ctx+ try:+ self.parse_cache = bld.parse_cache+ except AttributeError:+ bld.parse_cache = {}+ self.parse_cache = bld.parse_cache++ self.addlines(node)++ # macros may be defined on the command-line, so they must be parsed as if they were part of the file+ if env['DEFINES']:+ try:+ lst = ['%s %s' % (x[0], trimquotes('='.join(x[1:]))) for x in [y.split('=') for y in env['DEFINES']]]+ lst.reverse()+ self.lines.extend([('define', x) for x in lst])+ except AttributeError:+ # if the defines are invalid the compiler will tell the user+ pass++ while self.lines:+ (token, line) = self.lines.pop()+ if token == POPFILE:+ self.count_files -= 1+ self.currentnode_stack.pop()+ continue++ try:+ ve = Logs.verbose+ if ve: debug('preproc: line is %s - %s state is %s', token, line, self.state)+ state = self.state++ # make certain we define the state if we are about to enter in an if block+ if token[:2] == 'if':+ state.append(undefined)+ elif token == 'endif':+ state.pop()++ # skip lines when in a dead 'if' branch, wait for the endif+ if token[0] != 'e':+ if skipped in self.state or ignored in self.state:+ continue++ if token == 'if':+ ret = eval_macro(tokenize(line), self.defs)+ if ret: state[-1] = accepted+ else: state[-1] = ignored+ elif token == 'ifdef':+ m = re_mac.match(line)+ if m and m.group(0) in self.defs: state[-1] = accepted+ else: state[-1] = ignored+ elif token == 'ifndef':+ m = re_mac.match(line)+ if m and m.group(0) in self.defs: state[-1] = ignored+ else: state[-1] = accepted+ elif token == 'include' or token == 'import':+ (kind, inc) = extract_include(line, self.defs)+ if inc in self.ban_includes:+ continue+ if token == 'import': self.ban_includes.add(inc)+ if ve: debug('preproc: include found %s (%s) ', inc, kind)+ if kind == '"' or not strict_quotes:+ self.tryfind(inc)+ elif token == 'elif':+ if state[-1] == accepted:+ state[-1] = skipped+ elif state[-1] == ignored:+ if eval_macro(tokenize(line), self.defs):+ state[-1] = accepted+ elif token == 'else':+ if state[-1] == accepted: state[-1] = skipped+ elif state[-1] == ignored: state[-1] = accepted+ elif token == 'define':+ try:+ self.defs[define_name(line)] = line+ except Exception:+ raise PreprocError("Invalid define line %s" % line)+ elif token == 'undef':+ m = re_mac.match(line)+ if m and m.group(0) in self.defs:+ self.defs.__delitem__(m.group(0))+ #print "undef %s" % name+ elif token == 'pragma':+ if re_pragma_once.match(line.lower()):+ self.ban_includes.add(self.curfile)+ except Exception as e:+ if Logs.verbose:+ debug('preproc: line parsing failed (%s): %s %s', e, line, Utils.ex_stack())++def scan(task):+ """+ Get the dependencies using a c/c++ preprocessor, this is required for finding dependencies of the kind::++ #include some_macro()++ This function is bound as a task method on :py:class:`waflib.Tools.c.c` and :py:class:`waflib.Tools.cxx.cxx` for example+ """++ global go_absolute++ try:+ incn = task.generator.includes_nodes+ except AttributeError:+ raise Errors.WafError('%r is missing a feature such as "c", "cxx" or "includes": ' % task.generator)++ if go_absolute:+ nodepaths = incn + [task.generator.bld.root.find_dir(x) for x in standard_includes]+ else:+ nodepaths = [x for x in incn if x.is_child_of(x.ctx.srcnode) or x.is_child_of(x.ctx.bldnode)]++ tmp = c_parser(nodepaths)+ tmp.start(task.inputs[0], task.env)+ if Logs.verbose:+ debug('deps: deps for %r: %r; unresolved %r' % (task.inputs, tmp.nodes, tmp.names))+ return (tmp.nodes, tmp.names)+new file mode 100644@@ -0,0 +1,226 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010 (ita)++"""+Various configuration tests.+"""++from waflib import Task+from waflib.Configure import conf+from waflib.TaskGen import feature, before_method, after_method+import sys++LIB_CODE = '''+#ifdef _MSC_VER+#define testEXPORT __declspec(dllexport)+#else+#define testEXPORT+#endif+testEXPORT int lib_func(void) { return 9; }+'''++MAIN_CODE = '''+#ifdef _MSC_VER+#define testEXPORT __declspec(dllimport)+#else+#define testEXPORT+#endif+testEXPORT int lib_func(void);+int main(int argc, char **argv) {+ (void)argc; (void)argv;+ return !(lib_func() == 9);+}+'''++@feature('link_lib_test')+@before_method('process_source')+def link_lib_test_fun(self):+ """+ The configuration test :py:func:`waflib.Tools.ccroot.run_c_code` declares a unique task generator,+ so we need to create other task generators from here to check if the linker is able to link libraries.+ """+ def write_test_file(task):+ task.outputs[0].write(task.generator.code)++ rpath = []+ if getattr(self, 'add_rpath', False):+ rpath = [self.bld.path.get_bld().abspath()]++ mode = self.mode+ m = '%s %s' % (mode, mode)+ ex = self.test_exec and 'test_exec' or ''+ bld = self.bld+ bld(rule=write_test_file, target='test.' + mode, code=LIB_CODE)+ bld(rule=write_test_file, target='main.' + mode, code=MAIN_CODE)+ bld(features='%sshlib' % m, source='test.' + mode, target='test')+ bld(features='%sprogram %s' % (m, ex), source='main.' + mode, target='app', use='test', rpath=rpath)++@conf+def check_library(self, mode=None, test_exec=True):+ """+ Check if libraries can be linked with the current linker. Uses :py:func:`waflib.Tools.c_tests.link_lib_test_fun`.++ :param mode: c or cxx or d+ :type mode: string+ """+ if not mode:+ mode = 'c'+ if self.env.CXX:+ mode = 'cxx'+ self.check(+ compile_filename = [],+ features = 'link_lib_test',+ msg = 'Checking for libraries',+ mode = mode,+ test_exec = test_exec,+ )++########################################################################################++INLINE_CODE = '''+typedef int foo_t;+static %s foo_t static_foo () {return 0; }+%s foo_t foo () {+ return 0;+}+'''+INLINE_VALUES = ['inline', '__inline__', '__inline']++@conf+def check_inline(self, **kw):+ """+ Check for the right value for inline macro.+ Define INLINE_MACRO to 1 if the define is found.+ If the inline macro is not 'inline', add a define to the ``config.h`` (#define inline __inline__)++ :param define_name: define INLINE_MACRO by default to 1 if the macro is defined+ :type define_name: string+ :param features: by default *c* or *cxx* depending on the compiler present+ :type features: list of string+ """++ self.start_msg('Checking for inline')++ if not 'define_name' in kw:+ kw['define_name'] = 'INLINE_MACRO'+ if not 'features' in kw:+ if self.env.CXX:+ kw['features'] = ['cxx']+ else:+ kw['features'] = ['c']++ for x in INLINE_VALUES:+ kw['fragment'] = INLINE_CODE % (x, x)++ try:+ self.check(**kw)+ except self.errors.ConfigurationError:+ continue+ else:+ self.end_msg(x)+ if x != 'inline':+ self.define('inline', x, quote=False)+ return x+ self.fatal('could not use inline functions')++########################################################################################++LARGE_FRAGMENT = '''#include <unistd.h>+int main(int argc, char **argv) {+ (void)argc; (void)argv;+ return !(sizeof(off_t) >= 8);+}+'''++@conf+def check_large_file(self, **kw):+ """+ Check for large file support and define the macro HAVE_LARGEFILE+ The test is skipped on win32 systems (DEST_BINFMT == pe).++ :param define_name: define to set, by default *HAVE_LARGEFILE*+ :type define_name: string+ :param execute: execute the test (yes by default)+ :type execute: bool+ """++ if not 'define_name' in kw:+ kw['define_name'] = 'HAVE_LARGEFILE'+ if not 'execute' in kw:+ kw['execute'] = True++ if not 'features' in kw:+ if self.env.CXX:+ kw['features'] = ['cxx', 'cxxprogram']+ else:+ kw['features'] = ['c', 'cprogram']++ kw['fragment'] = LARGE_FRAGMENT++ kw['msg'] = 'Checking for large file support'+ ret = True+ try:+ if self.env.DEST_BINFMT != 'pe':+ ret = self.check(**kw)+ except self.errors.ConfigurationError:+ pass+ else:+ if ret:+ return True++ kw['msg'] = 'Checking for -D_FILE_OFFSET_BITS=64'+ kw['defines'] = ['_FILE_OFFSET_BITS=64']+ try:+ ret = self.check(**kw)+ except self.errors.ConfigurationError:+ pass+ else:+ self.define('_FILE_OFFSET_BITS', 64)+ return ret++ self.fatal('There is no support for large files')++########################################################################################++ENDIAN_FRAGMENT = '''+short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };+short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };+int use_ascii (int i) {+ return ascii_mm[i] + ascii_ii[i];+}+short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };+short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };+int use_ebcdic (int i) {+ return ebcdic_mm[i] + ebcdic_ii[i];+}+extern int foo;+'''++class grep_for_endianness(Task.Task):+ color = 'PINK'+ def run(self):+ txt = self.inputs[0].read(flags='rb').decode('iso8859-1')+ if txt.find('LiTTleEnDian') > -1:+ self.generator.tmp.append('little')+ elif txt.find('BIGenDianSyS') > -1:+ self.generator.tmp.append('big')+ else:+ return -1++@feature('grep_for_endianness')+@after_method('process_source')+def grep_for_endianness_fun(self):+ self.create_task('grep_for_endianness', self.compiled_tasks[0].outputs[0])++@conf+def check_endianness(self):+ """+ Execute a configuration test to determine the endianness+ """+ tmp = []+ def check_msg(self):+ return tmp[0]+ self.check(fragment=ENDIAN_FRAGMENT, features='c grep_for_endianness', msg="Checking for endianness", define='ENDIANNESS', tmp=tmp, okmsg=check_msg)+ return tmp[0]+new file mode 100644@@ -0,0 +1,640 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""+Classes and methods shared by tools providing support for C-like language such+as C/C++/D/Assembly/Go (this support module is almost never used alone).+"""++import os+from waflib import Task, Utils, Node, Errors+from waflib.TaskGen import after_method, before_method, feature, taskgen_method, extension+from waflib.Tools import c_aliases, c_preproc, c_config, c_osx, c_tests+from waflib.Configure import conf++SYSTEM_LIB_PATHS = ['/usr/lib64', '/usr/lib', '/usr/local/lib64', '/usr/local/lib']++USELIB_VARS = Utils.defaultdict(set)+"""+Mapping for features to :py:class:`waflib.ConfigSet.ConfigSet` variables. See :py:func:`waflib.Tools.ccroot.propagate_uselib_vars`.+"""++USELIB_VARS['c'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CCDEPS', 'CFLAGS', 'ARCH'])+USELIB_VARS['cxx'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CXXDEPS', 'CXXFLAGS', 'ARCH'])+USELIB_VARS['d'] = set(['INCLUDES', 'DFLAGS'])+USELIB_VARS['includes'] = set(['INCLUDES', 'FRAMEWORKPATH', 'ARCH'])++USELIB_VARS['cprogram'] = USELIB_VARS['cxxprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH'])+USELIB_VARS['cshlib'] = USELIB_VARS['cxxshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH'])+USELIB_VARS['cstlib'] = USELIB_VARS['cxxstlib'] = set(['ARFLAGS', 'LINKDEPS'])++USELIB_VARS['dprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])+USELIB_VARS['dshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])+USELIB_VARS['dstlib'] = set(['ARFLAGS', 'LINKDEPS'])++USELIB_VARS['asm'] = set(['ASFLAGS'])++# =================================================================================================++@taskgen_method+def create_compiled_task(self, name, node):+ """+ Create the compilation task: c, cxx, asm, etc. The output node is created automatically (object file with a typical **.o** extension).+ The task is appended to the list *compiled_tasks* which is then used by :py:func:`waflib.Tools.ccroot.apply_link`++ :param name: name of the task class+ :type name: string+ :param node: the file to compile+ :type node: :py:class:`waflib.Node.Node`+ :return: The task created+ :rtype: :py:class:`waflib.Task.Task`+ """+ out = '%s.%d.o' % (node.name, self.idx)+ task = self.create_task(name, node, node.parent.find_or_declare(out))+ try:+ self.compiled_tasks.append(task)+ except AttributeError:+ self.compiled_tasks = [task]+ return task++@taskgen_method+def to_incnodes(self, inlst):+ """+ Task generator method provided to convert a list of string/nodes into a list of includes folders.++ The paths are assumed to be relative to the task generator path, except if they begin by **#**+ in which case they are searched from the top-level directory (``bld.srcnode``).+ The folders are simply assumed to be existing.++ The node objects in the list are returned in the output list. The strings are converted+ into node objects if possible. The node is searched from the source directory, and if a match is found,+ the equivalent build directory is created and added to the returned list too. When a folder cannot be found, it is ignored.++ :param inlst: list of folders+ :type inlst: space-delimited string or a list of string/nodes+ :rtype: list of :py:class:`waflib.Node.Node`+ :return: list of include folders as nodes+ """+ lst = []+ seen = set([])+ for x in self.to_list(inlst):+ if x in seen or not x:+ continue+ seen.add(x)++ if isinstance(x, Node.Node):+ lst.append(x)+ else:+ if os.path.isabs(x):+ lst.append(self.bld.root.make_node(x) or x)+ else:+ if x[0] == '#':+ p = self.bld.bldnode.make_node(x[1:])+ v = self.bld.srcnode.make_node(x[1:])+ else:+ p = self.path.get_bld().make_node(x)+ v = self.path.make_node(x)+ if p.is_child_of(self.bld.bldnode):+ p.mkdir()+ lst.append(p)+ lst.append(v)+ return lst++@feature('c', 'cxx', 'd', 'asm', 'fc', 'includes')+@after_method('propagate_uselib_vars', 'process_source')+def apply_incpaths(self):+ """+ Task generator method that processes the attribute *includes*::++ tg = bld(features='includes', includes='.')++ The folders only need to be relative to the current directory, the equivalent build directory is+ added automatically (for headers created in the build directory). This enable using a build directory+ or not (``top == out``).++ This method will add a list of nodes read by :py:func:`waflib.Tools.ccroot.to_incnodes` in ``tg.env.INCPATHS``,+ and the list of include paths in ``tg.env.INCLUDES``.+ """++ lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env['INCLUDES'])+ self.includes_nodes = lst+ self.env['INCPATHS'] = [x.abspath() for x in lst]++class link_task(Task.Task):+ """+ Base class for all link tasks. A task generator is supposed to have at most one link task bound in the attribute *link_task*. See :py:func:`waflib.Tools.ccroot.apply_link`.++ .. inheritance-diagram:: waflib.Tools.ccroot.stlink_task waflib.Tools.c.cprogram waflib.Tools.c.cshlib waflib.Tools.cxx.cxxstlib waflib.Tools.cxx.cxxprogram waflib.Tools.cxx.cxxshlib waflib.Tools.d.dprogram waflib.Tools.d.dshlib waflib.Tools.d.dstlib waflib.Tools.ccroot.fake_shlib waflib.Tools.ccroot.fake_stlib waflib.Tools.asm.asmprogram waflib.Tools.asm.asmshlib waflib.Tools.asm.asmstlib+ """+ color = 'YELLOW'++ inst_to = None+ """Default installation path for the link task outputs, or None to disable"""++ chmod = Utils.O755+ """Default installation mode for the link task outputs"""++ def add_target(self, target):+ """+ Process the *target* attribute to add the platform-specific prefix/suffix such as *.so* or *.exe*.+ The settings are retrieved from ``env.clsname_PATTERN``+ """+ if isinstance(target, str):+ pattern = self.env[self.__class__.__name__ + '_PATTERN']+ if not pattern:+ pattern = '%s'+ folder, name = os.path.split(target)++ if self.__class__.__name__.find('shlib') > 0:+ if self.env.DEST_BINFMT == 'pe' and getattr(self.generator, 'vnum', None):+ # include the version in the dll file name,+ # the import lib file name stays unversionned.+ name = name + '-' + self.generator.vnum.split('.')[0]++ tmp = folder + os.sep + pattern % name+ target = self.generator.path.find_or_declare(tmp)+ self.set_outputs(target)++class stlink_task(link_task):+ """+ Base for static link tasks, which use *ar* most of the time.+ The target is always removed before being written.+ """+ run_str = '${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}'++def rm_tgt(cls):+ old = cls.run+ def wrap(self):+ try: os.remove(self.outputs[0].abspath())+ except OSError: pass+ return old(self)+ setattr(cls, 'run', wrap)+rm_tgt(stlink_task)++@feature('c', 'cxx', 'd', 'fc', 'asm')+@after_method('process_source')+def apply_link(self):+ """+ Collect the tasks stored in ``compiled_tasks`` (created by :py:func:`waflib.Tools.ccroot.create_compiled_task`), and+ use the outputs for a new instance of :py:class:`waflib.Tools.ccroot.link_task`. The class to use is the first link task+ matching a name from the attribute *features*, for example::++ def build(bld):+ tg = bld(features='cxx cxxprogram cprogram', source='main.c', target='app')++ will create the task ``tg.link_task`` as a new instance of :py:class:`waflib.Tools.cxx.cxxprogram`+ """++ for x in self.features:+ if x == 'cprogram' and 'cxx' in self.features: # limited compat+ x = 'cxxprogram'+ elif x == 'cshlib' and 'cxx' in self.features:+ x = 'cxxshlib'++ if x in Task.classes:+ if issubclass(Task.classes[x], link_task):+ link = x+ break+ else:+ return++ objs = [t.outputs[0] for t in getattr(self, 'compiled_tasks', [])]+ self.link_task = self.create_task(link, objs)+ self.link_task.add_target(self.target)++ # remember that the install paths are given by the task generators+ # we need to define install_task even during the build phase because others might need the installation path+ try:+ inst_to = self.install_path+ except AttributeError:+ inst_to = self.link_task.__class__.inst_to+ if inst_to:+ # install a copy of the node list we have at this moment (implib not added)+ self.install_task = self.bld.install_files(inst_to, self.link_task.outputs[:], env=self.env, chmod=self.link_task.chmod)++@taskgen_method+def use_rec(self, name, **kw):+ """+ Processes the ``use`` keyword recursively. This method is kind of private and only meant to be used from ``process_use``+ """++ if name in self.tmp_use_not or name in self.tmp_use_seen:+ return++ try:+ y = self.bld.get_tgen_by_name(name)+ except Errors.WafError:+ self.uselib.append(name)+ self.tmp_use_not.add(name)+ return++ self.tmp_use_seen.append(name)+ y.post()++ # bind temporary attributes on the task generator+ y.tmp_use_objects = objects = kw.get('objects', True)+ y.tmp_use_stlib = stlib = kw.get('stlib', True)+ try:+ link_task = y.link_task+ except AttributeError:+ y.tmp_use_var = ''+ else:+ objects = False+ if not isinstance(link_task, stlink_task):+ stlib = False+ y.tmp_use_var = 'LIB'+ else:+ y.tmp_use_var = 'STLIB'++ p = self.tmp_use_prec+ for x in self.to_list(getattr(y, 'use', [])):+ try:+ p[x].append(name)+ except KeyError:+ p[x] = [name]+ self.use_rec(x, objects=objects, stlib=stlib)++@feature('c', 'cxx', 'd', 'use', 'fc')+@before_method('apply_incpaths', 'propagate_uselib_vars')+@after_method('apply_link', 'process_source')+def process_use(self):+ """+ Process the ``use`` attribute which contains a list of task generator names::++ def build(bld):+ bld.shlib(source='a.c', target='lib1')+ bld.program(source='main.c', target='app', use='lib1')++ See :py:func:`waflib.Tools.ccroot.use_rec`.+ """++ use_not = self.tmp_use_not = set([])+ self.tmp_use_seen = [] # we would like an ordered set+ use_prec = self.tmp_use_prec = {}+ self.uselib = self.to_list(getattr(self, 'uselib', []))+ self.includes = self.to_list(getattr(self, 'includes', []))+ names = self.to_list(getattr(self, 'use', []))++ for x in names:+ self.use_rec(x)++ for x in use_not:+ if x in use_prec:+ del use_prec[x]++ # topological sort+ out = []+ tmp = []+ for x in self.tmp_use_seen:+ for k in use_prec.values():+ if x in k:+ break+ else:+ tmp.append(x)++ while tmp:+ e = tmp.pop()+ out.append(e)+ try:+ nlst = use_prec[e]+ except KeyError:+ pass+ else:+ del use_prec[e]+ for x in nlst:+ for y in use_prec:+ if x in use_prec[y]:+ break+ else:+ tmp.append(x)+ if use_prec:+ raise Errors.WafError('Cycle detected in the use processing %r' % use_prec)+ out.reverse()++ link_task = getattr(self, 'link_task', None)+ for x in out:+ y = self.bld.get_tgen_by_name(x)+ var = y.tmp_use_var+ if var and link_task:+ if var == 'LIB' or y.tmp_use_stlib:+ self.env.append_value(var, [y.target[y.target.rfind(os.sep) + 1:]])+ self.link_task.dep_nodes.extend(y.link_task.outputs)+ tmp_path = y.link_task.outputs[0].parent.path_from(self.bld.bldnode)+ self.env.append_value(var + 'PATH', [tmp_path])+ else:+ if y.tmp_use_objects:+ self.add_objects_from_tgen(y)++ if getattr(y, 'export_includes', None):+ self.includes.extend(y.to_incnodes(y.export_includes))++ # and finally, add the uselib variables (no recursion needed)+ for x in names:+ try:+ y = self.bld.get_tgen_by_name(x)+ except Exception:+ if not self.env['STLIB_' + x] and not x in self.uselib:+ self.uselib.append(x)+ else:+ for k in self.to_list(getattr(y, 'uselib', [])):+ if not self.env['STLIB_' + k] and not k in self.uselib:+ self.uselib.append(k)++@taskgen_method+def accept_node_to_link(self, node):+ """+ PRIVATE INTERNAL USE ONLY+ """+ return not node.name.endswith('.pdb')++@taskgen_method+def add_objects_from_tgen(self, tg):+ """+ Add the objects from the depending compiled tasks as link task inputs.++ Some objects are filtered: for instance, .pdb files are added+ to the compiled tasks but not to the link tasks (to avoid errors)+ PRIVATE INTERNAL USE ONLY+ """+ try:+ link_task = self.link_task+ except AttributeError:+ pass+ else:+ for tsk in getattr(tg, 'compiled_tasks', []):+ for x in tsk.outputs:+ if self.accept_node_to_link(x):+ link_task.inputs.append(x)++@taskgen_method+def get_uselib_vars(self):+ """+ :return: the *uselib* variables associated to the *features* attribute (see :py:attr:`waflib.Tools.ccroot.USELIB_VARS`)+ :rtype: list of string+ """+ _vars = set([])+ for x in self.features:+ if x in USELIB_VARS:+ _vars |= USELIB_VARS[x]+ return _vars++@feature('c', 'cxx', 'd', 'fc', 'javac', 'cs', 'uselib', 'asm')+@after_method('process_use')+def propagate_uselib_vars(self):+ """+ Process uselib variables for adding flags. For example, the following target::++ def build(bld):+ bld.env.AFLAGS_aaa = ['bar']+ from waflib.Tools.ccroot import USELIB_VARS+ USELIB_VARS['aaa'] = set('AFLAGS')++ tg = bld(features='aaa', aflags='test')++ The *aflags* attribute will be processed and this method will set::++ tg.env.AFLAGS = ['bar', 'test']+ """+ _vars = self.get_uselib_vars()+ env = self.env++ for x in _vars:+ y = x.lower()+ env.append_unique(x, self.to_list(getattr(self, y, [])))++ for x in self.features:+ for var in _vars:+ compvar = '%s_%s' % (var, x)+ env.append_value(var, env[compvar])++ for x in self.to_list(getattr(self, 'uselib', [])):+ for v in _vars:+ env.append_value(v, env[v + '_' + x])++# ============ the code above must not know anything about import libs ==========++@feature('cshlib', 'cxxshlib', 'fcshlib')+@after_method('apply_link')+def apply_implib(self):+ """+ Handle dlls and their import libs on Windows-like systems.++ A ``.dll.a`` file called *import library* is generated.+ It must be installed as it is required for linking the library.+ """+ if not self.env.DEST_BINFMT == 'pe':+ return++ dll = self.link_task.outputs[0]+ if isinstance(self.target, Node.Node):+ name = self.target.name+ else:+ name = os.path.split(self.target)[1]+ implib = self.env['implib_PATTERN'] % name+ implib = dll.parent.find_or_declare(implib)+ self.env.append_value('LINKFLAGS', self.env['IMPLIB_ST'] % implib.bldpath())+ self.link_task.outputs.append(implib)++ if getattr(self, 'defs', None) and self.env.DEST_BINFMT == 'pe':+ node = self.path.find_resource(self.defs)+ if not node:+ raise Errors.WafError('invalid def file %r' % self.defs)+ if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):+ self.env.append_value('LINKFLAGS', '/def:%s' % node.path_from(self.bld.bldnode))+ self.link_task.dep_nodes.append(node)+ else:+ #gcc for windows takes *.def file a an input without any special flag+ self.link_task.inputs.append(node)++ try:+ inst_to = self.install_path+ except AttributeError:+ inst_to = self.link_task.__class__.inst_to+ if not inst_to:+ return++ self.implib_install_task = self.bld.install_as('${PREFIX}/lib/%s' % implib.name, implib, self.env)++# ============ the code above must not know anything about vnum processing on unix platforms =========++@feature('cshlib', 'cxxshlib', 'dshlib', 'fcshlib', 'vnum')+@after_method('apply_link')+def apply_vnum(self):+ """+ Enforce version numbering on shared libraries. The valid version numbers must have at most two dots::++ def build(bld):+ bld.shlib(source='a.c', target='foo', vnum='14.15.16')++ In this example, ``libfoo.so`` is installed as ``libfoo.so.1.2.3``, and the following symbolic links are created:++ * ``libfoo.so → libfoo.so.1.2.3``+ * ``libfoo.so.1 → libfoo.so.1.2.3``+ """+ if not getattr(self, 'vnum', '') or os.name != 'posix' or self.env.DEST_BINFMT not in ('elf', 'mac-o'):+ return++ link = self.link_task+ nums = self.vnum.split('.')+ node = link.outputs[0]++ libname = node.name+ if libname.endswith('.dylib'):+ name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum)+ name2 = libname.replace('.dylib', '.%s.dylib' % nums[0])+ else:+ name3 = libname + '.' + self.vnum+ name2 = libname + '.' + nums[0]++ # add the so name for the ld linker - to disable, just unset env.SONAME_ST+ if self.env.SONAME_ST:+ v = self.env.SONAME_ST % name2+ self.env.append_value('LINKFLAGS', v.split())++ # the following task is just to enable execution from the build dir :-/+ self.create_task('vnum', node, [node.parent.find_or_declare(name2), node.parent.find_or_declare(name3)])++ if getattr(self.bld, 'is_install', None):+ self.install_task.hasrun = Task.SKIP_ME+ bld = self.bld+ path = self.install_task.dest+ t1 = bld.install_as(path + os.sep + name3, node, env=self.env, chmod=self.link_task.chmod)+ t2 = bld.symlink_as(path + os.sep + name2, name3)+ t3 = bld.symlink_as(path + os.sep + libname, name3)+ self.vnum_install_task = (t1, t2, t3)++ if '-dynamiclib' in self.env['LINKFLAGS'] and getattr(self, 'install_task', None):+ path = os.path.join(self.install_task.get_install_path(), self.link_task.outputs[0].name)+ self.env.append_value('LINKFLAGS', ['-install_name', path])++class vnum(Task.Task):+ """+ Create the symbolic links for a versioned shared library. Instances are created by :py:func:`waflib.Tools.ccroot.apply_vnum`+ """+ color = 'CYAN'+ quient = True+ ext_in = ['.bin']+ def run(self):+ for x in self.outputs:+ path = x.abspath()+ try:+ os.remove(path)+ except OSError:+ pass++ try:+ os.symlink(self.inputs[0].name, path)+ except OSError:+ return 1++class fake_shlib(link_task):+ """+ Task used for reading a system library and adding the dependency on it+ """+ def runnable_status(self):+ for t in self.run_after:+ if not t.hasrun:+ return Task.ASK_LATER++ for x in self.outputs:+ x.sig = Utils.h_file(x.abspath())+ return Task.SKIP_ME++class fake_stlib(stlink_task):+ """+ Task used for reading a system library and adding the dependency on it+ """+ def runnable_status(self):+ for t in self.run_after:+ if not t.hasrun:+ return Task.ASK_LATER++ for x in self.outputs:+ x.sig = Utils.h_file(x.abspath())+ return Task.SKIP_ME++@conf+def read_shlib(self, name, paths=[]):+ """+ Read a system shared library, enabling its use as a local library. Will trigger a rebuild if the file changes::++ def build(bld):+ bld.read_shlib('m')+ bld.program(source='main.c', use='m')+ """+ return self(name=name, features='fake_lib', lib_paths=paths, lib_type='shlib')++@conf+def read_stlib(self, name, paths=[]):+ """+ Read a system static library, enabling a use as a local library. Will trigger a rebuild if the file changes.+ """+ return self(name=name, features='fake_lib', lib_paths=paths, lib_type='stlib')++lib_patterns = {+ 'shlib' : ['lib%s.so', '%s.so', 'lib%s.dylib', 'lib%s.dll', '%s.dll'],+ 'stlib' : ['lib%s.a', '%s.a', 'lib%s.dll', '%s.dll', 'lib%s.lib', '%s.lib'],+}++@feature('fake_lib')+def process_lib(self):+ """+ Find the location of a foreign library. Used by :py:class:`waflib.Tools.ccroot.read_shlib` and :py:class:`waflib.Tools.ccroot.read_stlib`.+ """+ node = None++ names = [x % self.name for x in lib_patterns[self.lib_type]]+ for x in self.lib_paths + [self.path] + SYSTEM_LIB_PATHS:+ if not isinstance(x, Node.Node):+ x = self.bld.root.find_node(x) or self.path.find_node(x)+ if not x:+ continue++ for y in names:+ node = x.find_node(y)+ if node:+ node.sig = Utils.h_file(node.abspath())+ break+ else:+ continue+ break+ else:+ raise Errors.WafError('could not find library %r' % self.name)+ self.link_task = self.create_task('fake_%s' % self.lib_type, [], [node])+ self.target = self.name+++class fake_o(Task.Task):+ def runnable_status(self):+ return Task.SKIP_ME++@extension('.o', '.obj')+def add_those_o_files(self, node):+ tsk = self.create_task('fake_o', [], node)+ try:+ self.compiled_tasks.append(tsk)+ except AttributeError:+ self.compiled_tasks = [tsk]++@feature('fake_obj')+@before_method('process_source')+def process_objs(self):+ """+ Puts object files in the task generator outputs+ """+ for node in self.to_nodes(self.source):+ self.add_those_o_files(node)+ self.source = []++@conf+def read_object(self, obj):+ """+ Read an object file, enabling injection in libs/programs. Will trigger a rebuild if the file changes.++ :param obj: object file path, as string or Node+ """+ if not isinstance(obj, self.path.__class__):+ obj = self.path.find_resource(obj)+ return self(features='fake_obj', source=obj, name=obj.name)+new file mode 100644@@ -0,0 +1,98 @@+#!/usr/bin/env python+# encoding: utf-8+# Matthias Jahn jahn dôt matthias ât freenet dôt de, 2007 (pmarat)++"""+Try to detect a C compiler from the list of supported compilers (gcc, msvc, etc)::++ def options(opt):+ opt.load('compiler_c')+ def configure(cnf):+ cnf.load('compiler_c')+ def build(bld):+ bld.program(source='main.c', target='app')++The compilers are associated to platforms in :py:attr:`waflib.Tools.compiler_c.c_compiler`. To register+a new C compiler named *cfoo* (assuming the tool ``waflib/extras/cfoo.py`` exists), use::++ def options(opt):+ opt.load('compiler_c')+ def configure(cnf):+ from waflib.Tools.compiler_c import c_compiler+ c_compiler['win32'] = ['cfoo', 'msvc', 'gcc']+ cnf.load('compiler_c')+ def build(bld):+ bld.program(source='main.c', target='app')++Not all compilers need to have a specific tool. For example, the clang compilers can be detected by the gcc tools when using::++ $ CC=clang waf configure+"""++import os, sys, imp, types+from waflib.Tools import ccroot+from waflib import Utils, Configure+from waflib.Logs import debug++c_compiler = {+'win32': ['msvc', 'gcc'],+'cygwin': ['gcc'],+'darwin': ['gcc'],+'aix': ['xlc', 'gcc'],+'linux': ['gcc', 'icc'],+'sunos': ['suncc', 'gcc'],+'irix': ['gcc', 'irixcc'],+'hpux': ['gcc'],+'gnu': ['gcc'],+'java': ['gcc', 'msvc', 'icc'],+'default':['gcc'],+}+"""+Dict mapping the platform names to waf tools finding specific compilers::++ from waflib.Tools.compiler_c import c_compiler+ c_compiler['linux'] = ['gcc', 'icc', 'suncc']+"""++def configure(conf):+ """+ Try to find a suitable C compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.+ """+ try: test_for_compiler = conf.options.check_c_compiler+ except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_c')")+ for compiler in test_for_compiler.split():+ conf.env.stash()+ conf.start_msg('Checking for %r (c compiler)' % compiler)+ try:+ conf.load(compiler)+ except conf.errors.ConfigurationError as e:+ conf.env.revert()+ conf.end_msg(False)+ debug('compiler_c: %r' % e)+ else:+ if conf.env['CC']:+ conf.end_msg(conf.env.get_flat('CC'))+ conf.env['COMPILER_CC'] = compiler+ break+ conf.end_msg(False)+ else:+ conf.fatal('could not configure a c compiler!')++def options(opt):+ """+ Restrict the compiler detection from the command-line::++ $ waf configure --check-c-compiler=gcc+ """+ opt.load_special_tools('c_*.py', ban=['c_dumbpreproc.py'])+ global c_compiler+ build_platform = Utils.unversioned_sys_platform()+ possible_compiler_list = c_compiler[build_platform in c_compiler and build_platform or 'default']+ test_for_compiler = ' '.join(possible_compiler_list)+ cc_compiler_opts = opt.add_option_group("C Compiler Options")+ cc_compiler_opts.add_option('--check-c-compiler', default="%s" % test_for_compiler,+ help='On this platform (%s) the following C-Compiler will be checked by default: "%s"' % (build_platform, test_for_compiler),+ dest="check_c_compiler")+ for x in test_for_compiler.split():+ opt.load('%s' % x)+new file mode 100644@@ -0,0 +1,102 @@+#!/usr/bin/env python+# encoding: utf-8+# Matthias Jahn jahn dôt matthias ât freenet dôt de 2007 (pmarat)++"""+Try to detect a C++ compiler from the list of supported compilers (g++, msvc, etc)::++ def options(opt):+ opt.load('compiler_cxx')+ def configure(cnf):+ cnf.load('compiler_cxx')+ def build(bld):+ bld.program(source='main.cpp', target='app')++The compilers are associated to platforms in :py:attr:`waflib.Tools.compiler_cxx.cxx_compiler`. To register+a new C++ compiler named *cfoo* (assuming the tool ``waflib/extras/cfoo.py`` exists), use::++ def options(opt):+ opt.load('compiler_cxx')+ def configure(cnf):+ from waflib.Tools.compiler_cxx import cxx_compiler+ cxx_compiler['win32'] = ['cfoo', 'msvc', 'gcc']+ cnf.load('compiler_cxx')+ def build(bld):+ bld.program(source='main.c', target='app')++Not all compilers need to have a specific tool. For example, the clang compilers can be detected by the gcc tools when using::++ $ CXX=clang waf configure+"""+++import os, sys, imp, types+from waflib.Tools import ccroot+from waflib import Utils, Configure+from waflib.Logs import debug++cxx_compiler = {+'win32': ['msvc', 'g++'],+'cygwin': ['g++'],+'darwin': ['g++'],+'aix': ['xlc++', 'g++'],+'linux': ['g++', 'icpc'],+'sunos': ['sunc++', 'g++'],+'irix': ['g++'],+'hpux': ['g++'],+'gnu': ['g++'],+'java': ['g++', 'msvc', 'icpc'],+'default': ['g++']+}+"""+Dict mapping the platform names to waf tools finding specific compilers::++ from waflib.Tools.compiler_cxx import cxx_compiler+ cxx_compiler['linux'] = ['gxx', 'icpc', 'suncxx']+"""+++def configure(conf):+ """+ Try to find a suitable C++ compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.+ """+ try: test_for_compiler = conf.options.check_cxx_compiler+ except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_cxx')")++ for compiler in test_for_compiler.split():+ conf.env.stash()+ conf.start_msg('Checking for %r (c++ compiler)' % compiler)+ try:+ conf.load(compiler)+ except conf.errors.ConfigurationError as e:+ conf.env.revert()+ conf.end_msg(False)+ debug('compiler_cxx: %r' % e)+ else:+ if conf.env['CXX']:+ conf.end_msg(conf.env.get_flat('CXX'))+ conf.env['COMPILER_CXX'] = compiler+ break+ conf.end_msg(False)+ else:+ conf.fatal('could not configure a c++ compiler!')++def options(opt):+ """+ Restrict the compiler detection from the command-line::++ $ waf configure --check-cxx-compiler=gxx+ """+ opt.load_special_tools('cxx_*.py')+ global cxx_compiler+ build_platform = Utils.unversioned_sys_platform()+ possible_compiler_list = cxx_compiler[build_platform in cxx_compiler and build_platform or 'default']+ test_for_compiler = ' '.join(possible_compiler_list)+ cxx_compiler_opts = opt.add_option_group('C++ Compiler Options')+ cxx_compiler_opts.add_option('--check-cxx-compiler', default="%s" % test_for_compiler,+ help='On this platform (%s) the following C++ Compiler will be checked by default: "%s"' % (build_platform, test_for_compiler),+ dest="check_cxx_compiler")++ for x in test_for_compiler.split():+ opt.load('%s' % x)+new file mode 100644@@ -0,0 +1,59 @@+#!/usr/bin/env python+# encoding: utf-8+# Carlos Rafael Giani, 2007 (dv)+# Thomas Nagy, 2010 (ita)++"""+Try to detect a D compiler from the list of supported compilers::++ def options(opt):+ opt.load('compiler_d')+ def configure(cnf):+ cnf.load('compiler_d')+ def build(bld):+ bld.program(source='main.d', target='app')++Only three D compilers are really present at the moment:++* gdc+* dmd, the ldc compiler having a very similar command-line interface+* ldc2+"""++import os, sys, imp, types+from waflib import Utils, Configure, Options, Logs++def configure(conf):+ """+ Try to find a suitable D compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.+ """+ for compiler in conf.options.dcheck.split(','):+ conf.env.stash()+ conf.start_msg('Checking for %r (d compiler)' % compiler)+ try:+ conf.load(compiler)+ except conf.errors.ConfigurationError as e:+ conf.env.revert()+ conf.end_msg(False)+ Logs.debug('compiler_d: %r' % e)+ else:+ if conf.env.D:+ conf.end_msg(conf.env.get_flat('D'))+ conf.env['COMPILER_D'] = compiler+ break+ conf.end_msg(False)+ else:+ conf.fatal('no suitable d compiler was found')++def options(opt):+ """+ Restrict the compiler detection from the command-line::++ $ waf configure --check-d-compiler=dmd+ """+ d_compiler_opts = opt.add_option_group('D Compiler Options')+ d_compiler_opts.add_option('--check-d-compiler', default='gdc,dmd,ldc2', action='store',+ help='check for the compiler [Default:gdc,dmd,ldc2]', dest='dcheck')+ for d_compiler in ['gdc', 'dmd', 'ldc2']:+ opt.load('%s' % d_compiler)+new file mode 100644@@ -0,0 +1,66 @@+#!/usr/bin/env python+# encoding: utf-8++import os, sys, imp, types+from waflib import Utils, Configure, Options, Logs, Errors+from waflib.Tools import fc++fc_compiler = {+ 'win32' : ['gfortran','ifort'],+ 'darwin' : ['gfortran', 'g95', 'ifort'],+ 'linux' : ['gfortran', 'g95', 'ifort'],+ 'java' : ['gfortran', 'g95', 'ifort'],+ 'default': ['gfortran'],+ 'aix' : ['gfortran']+}++def __list_possible_compiler(platform):+ try:+ return fc_compiler[platform]+ except KeyError:+ return fc_compiler["default"]++def configure(conf):+ """+ Try to find a suitable Fortran compiler or raise a :py:class:`waflib.Errors.ConfigurationError`.+ """+ try: test_for_compiler = conf.options.check_fc+ except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_fc')")+ for compiler in test_for_compiler.split():+ conf.env.stash()+ conf.start_msg('Checking for %r (fortran compiler)' % compiler)+ try:+ conf.load(compiler)+ except conf.errors.ConfigurationError as e:+ conf.env.revert()+ conf.end_msg(False)+ Logs.debug('compiler_fortran: %r' % e)+ else:+ if conf.env['FC']:+ conf.end_msg(conf.env.get_flat('FC'))+ conf.env.COMPILER_FORTRAN = compiler+ break+ conf.end_msg(False)+ else:+ conf.fatal('could not configure a fortran compiler!')++def options(opt):+ """+ Restrict the compiler detection from the command-line::++ $ waf configure --check-fortran-compiler=ifort+ """+ opt.load_special_tools('fc_*.py')+ build_platform = Utils.unversioned_sys_platform()+ detected_platform = Options.platform+ possible_compiler_list = __list_possible_compiler(detected_platform)+ test_for_compiler = ' '.join(possible_compiler_list)+ fortran_compiler_opts = opt.add_option_group("Fortran Compiler Options")+ fortran_compiler_opts.add_option('--check-fortran-compiler',+ default="%s" % test_for_compiler,+ help='On this platform (%s) the following Fortran Compiler will be checked by default: "%s"' % (detected_platform, test_for_compiler),+ dest="check_fc")++ for compiler in test_for_compiler.split():+ opt.load('%s' % compiler)+new file mode 100644@@ -0,0 +1,222 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+C# support. A simple example::++ def configure(conf):+ conf.load('cs')+ def build(bld):+ bld(features='cs', source='main.cs', gen='foo')++Note that the configuration may compile C# snippets::++ FRAG = '''+ namespace Moo {+ public class Test { public static int Main(string[] args) { return 0; } }+ }'''+ def configure(conf):+ conf.check(features='cs', fragment=FRAG, compile_filename='test.cs', gen='test.exe',+ bintype='exe', csflags=['-pkg:gtk-sharp-2.0'], msg='Checking for Gtksharp support')+"""++from waflib import Utils, Task, Options, Logs, Errors+from waflib.TaskGen import before_method, after_method, feature+from waflib.Tools import ccroot+from waflib.Configure import conf+import os, tempfile++ccroot.USELIB_VARS['cs'] = set(['CSFLAGS', 'ASSEMBLIES', 'RESOURCES'])+ccroot.lib_patterns['csshlib'] = ['%s']++@feature('cs')+@before_method('process_source')+def apply_cs(self):+ """+ Create a C# task bound to the attribute *cs_task*. There can be only one C# task by task generator.+ """+ cs_nodes = []+ no_nodes = []+ for x in self.to_nodes(self.source):+ if x.name.endswith('.cs'):+ cs_nodes.append(x)+ else:+ no_nodes.append(x)+ self.source = no_nodes++ bintype = getattr(self, 'bintype', self.gen.endswith('.dll') and 'library' or 'exe')+ self.cs_task = tsk = self.create_task('mcs', cs_nodes, self.path.find_or_declare(self.gen))+ tsk.env.CSTYPE = '/target:%s' % bintype+ tsk.env.OUT = '/out:%s' % tsk.outputs[0].abspath()+ self.env.append_value('CSFLAGS', '/platform:%s' % getattr(self, 'platform', 'anycpu'))++ inst_to = getattr(self, 'install_path', bintype=='exe' and '${BINDIR}' or '${LIBDIR}')+ if inst_to:+ # note: we are making a copy, so the files added to cs_task.outputs won't be installed automatically+ mod = getattr(self, 'chmod', bintype=='exe' and Utils.O755 or Utils.O644)+ self.install_task = self.bld.install_files(inst_to, self.cs_task.outputs[:], env=self.env, chmod=mod)++@feature('cs')+@after_method('apply_cs')+def use_cs(self):+ """+ C# applications honor the **use** keyword::++ def build(bld):+ bld(features='cs', source='My.cs', bintype='library', gen='my.dll', name='mylib')+ bld(features='cs', source='Hi.cs', includes='.', bintype='exe', gen='hi.exe', use='mylib', name='hi')+ """+ names = self.to_list(getattr(self, 'use', []))+ get = self.bld.get_tgen_by_name+ for x in names:+ try:+ y = get(x)+ except Errors.WafError:+ self.env.append_value('CSFLAGS', '/reference:%s' % x)+ continue+ y.post()++ tsk = getattr(y, 'cs_task', None) or getattr(y, 'link_task', None)+ if not tsk:+ self.bld.fatal('cs task has no link task for use %r' % self)+ self.cs_task.dep_nodes.extend(tsk.outputs) # dependency+ self.cs_task.set_run_after(tsk) # order (redundant, the order is infered from the nodes inputs/outputs)+ self.env.append_value('CSFLAGS', '/reference:%s' % tsk.outputs[0].abspath())++@feature('cs')+@after_method('apply_cs', 'use_cs')+def debug_cs(self):+ """+ The C# targets may create .mdb or .pdb files::++ def build(bld):+ bld(features='cs', source='My.cs', bintype='library', gen='my.dll', csdebug='full')+ # csdebug is a value in [True, 'full', 'pdbonly']+ """+ csdebug = getattr(self, 'csdebug', self.env.CSDEBUG)+ if not csdebug:+ return++ node = self.cs_task.outputs[0]+ if self.env.CS_NAME == 'mono':+ out = node.parent.find_or_declare(node.name + '.mdb')+ else:+ out = node.change_ext('.pdb')+ self.cs_task.outputs.append(out)+ try:+ self.install_task.source.append(out)+ except AttributeError:+ pass++ if csdebug == 'pdbonly':+ val = ['/debug+', '/debug:pdbonly']+ elif csdebug == 'full':+ val = ['/debug+', '/debug:full']+ else:+ val = ['/debug-']+ self.env.append_value('CSFLAGS', val)+++class mcs(Task.Task):+ """+ Compile C# files+ """+ color = 'YELLOW'+ run_str = '${MCS} ${CSTYPE} ${CSFLAGS} ${ASS_ST:ASSEMBLIES} ${RES_ST:RESOURCES} ${OUT} ${SRC}'++ def exec_command(self, cmd, **kw):+ bld = self.generator.bld++ try:+ if not kw.get('cwd', None):+ kw['cwd'] = bld.cwd+ except AttributeError:+ bld.cwd = kw['cwd'] = bld.variant_dir++ try:+ tmp = None+ if isinstance(cmd, list) and len(' '.join(cmd)) >= 8192:+ program = cmd[0] #unquoted program name, otherwise exec_command will fail+ cmd = [self.quote_response_command(x) for x in cmd]+ (fd, tmp) = tempfile.mkstemp()+ os.write(fd, '\r\n'.join(i.replace('\\', '\\\\') for i in cmd[1:]).encode())+ os.close(fd)+ cmd = [program, '@' + tmp]+ # no return here, that's on purpose+ ret = self.generator.bld.exec_command(cmd, **kw)+ finally:+ if tmp:+ try:+ os.remove(tmp)+ except OSError:+ pass # anti-virus and indexers can keep the files open -_-+ return ret++ def quote_response_command(self, flag):+ # /noconfig is not allowed when using response files+ if flag.lower() == '/noconfig':+ return ''++ if flag.find(' ') > -1:+ for x in ('/r:', '/reference:', '/resource:', '/lib:', '/out:'):+ if flag.startswith(x):+ flag = '%s"%s"' % (x, flag[len(x):])+ break+ else:+ flag = '"%s"' % flag+ return flag++def configure(conf):+ """+ Find a C# compiler, set the variable MCS for the compiler and CS_NAME (mono or csc)+ """+ csc = getattr(Options.options, 'cscbinary', None)+ if csc:+ conf.env.MCS = csc+ conf.find_program(['csc', 'mcs', 'gmcs'], var='MCS')+ conf.env.ASS_ST = '/r:%s'+ conf.env.RES_ST = '/resource:%s'++ conf.env.CS_NAME = 'csc'+ if str(conf.env.MCS).lower().find('mcs') > -1:+ conf.env.CS_NAME = 'mono'++def options(opt):+ """+ Add a command-line option for the configuration::++ $ waf configure --with-csc-binary=/foo/bar/mcs+ """+ opt.add_option('--with-csc-binary', type='string', dest='cscbinary')++class fake_csshlib(Task.Task):+ """+ Task used for reading a foreign .net assembly and adding the dependency on it+ """+ color = 'YELLOW'+ inst_to = None++ def runnable_status(self):+ for x in self.outputs:+ x.sig = Utils.h_file(x.abspath())+ return Task.SKIP_ME++@conf+def read_csshlib(self, name, paths=[]):+ """+ Read a foreign .net assembly for the *use* system::++ def build(bld):+ bld.read_csshlib('ManagedLibrary.dll', paths=[bld.env.mylibrarypath])+ bld(features='cs', source='Hi.cs', bintype='exe', gen='hi.exe', use='ManagedLibrary.dll')++ :param name: Name of the library+ :type name: string+ :param paths: Folders in which the library may be found+ :type paths: list of string+ :return: A task generator having the feature *fake_lib* which will call :py:func:`waflib.Tools.ccroot.process_lib`+ :rtype: :py:class:`waflib.TaskGen.task_gen`+ """+ return self(name=name, features='fake_lib', lib_paths=paths, lib_type='csshlib')+new file mode 100644@@ -0,0 +1,40 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"Base for c++ programs and libraries"++from waflib import TaskGen, Task, Utils+from waflib.Tools import c_preproc+from waflib.Tools.ccroot import link_task, stlink_task++@TaskGen.extension('.cpp','.cc','.cxx','.C','.c++')+def cxx_hook(self, node):+ "Bind the c++ file extensions to the creation of a :py:class:`waflib.Tools.cxx.cxx` instance"+ return self.create_compiled_task('cxx', node)++if not '.c' in TaskGen.task_gen.mappings:+ TaskGen.task_gen.mappings['.c'] = TaskGen.task_gen.mappings['.cpp']++class cxx(Task.Task):+ "Compile C++ files into object files"+ run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT}'+ vars = ['CXXDEPS'] # unused variable to depend on, just in case+ ext_in = ['.h'] # set the build order easily by using ext_out=['.h']+ scan = c_preproc.scan++class cxxprogram(link_task):+ "Link object files into a c++ program"+ run_str = '${LINK_CXX} ${LINKFLAGS} ${CXXLNK_SRC_F}${SRC} ${CXXLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB}'+ vars = ['LINKDEPS']+ ext_out = ['.bin']+ inst_to = '${BINDIR}'++class cxxshlib(cxxprogram):+ "Link object files into a c++ shared library"+ inst_to = '${LIBDIR}'++class cxxstlib(stlink_task):+ "Link object files into a c++ static library"+ pass # do not remove+new file mode 100644@@ -0,0 +1,97 @@+#!/usr/bin/env python+# encoding: utf-8+# Carlos Rafael Giani, 2007 (dv)+# Thomas Nagy, 2007-2010 (ita)++from waflib import Utils, Task, Errors+from waflib.TaskGen import taskgen_method, feature, extension+from waflib.Tools import d_scan, d_config+from waflib.Tools.ccroot import link_task, stlink_task++class d(Task.Task):+ "Compile a d file into an object file"+ color = 'GREEN'+ run_str = '${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_SRC_F:SRC} ${D_TGT_F:TGT}'+ scan = d_scan.scan++class d_with_header(d):+ "Compile a d file and generate a header"+ run_str = '${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_HDR_F:tgt.outputs[1].bldpath()} ${D_SRC_F:SRC} ${D_TGT_F:tgt.outputs[0].bldpath()}'++class d_header(Task.Task):+ "Compile d headers"+ color = 'BLUE'+ run_str = '${D} ${D_HEADER} ${SRC}'++class dprogram(link_task):+ "Link object files into a d program"+ run_str = '${D_LINKER} ${LINKFLAGS} ${DLNK_SRC_F}${SRC} ${DLNK_TGT_F:TGT} ${RPATH_ST:RPATH} ${DSTLIB_MARKER} ${DSTLIBPATH_ST:STLIBPATH} ${DSTLIB_ST:STLIB} ${DSHLIB_MARKER} ${DLIBPATH_ST:LIBPATH} ${DSHLIB_ST:LIB}'+ inst_to = '${BINDIR}'++class dshlib(dprogram):+ "Link object files into a d shared library"+ inst_to = '${LIBDIR}'++class dstlib(stlink_task):+ "Link object files into a d static library"+ pass # do not remove++@extension('.d', '.di', '.D')+def d_hook(self, node):+ """+ Compile *D* files. To get .di files as well as .o files, set the following::++ def build(bld):+ bld.program(source='foo.d', target='app', generate_headers=True)++ """+ ext = Utils.destos_to_binfmt(self.env.DEST_OS) == 'pe' and 'obj' or 'o'+ out = '%s.%d.%s' % (node.name, self.idx, ext)+ def create_compiled_task(self, name, node):+ task = self.create_task(name, node, node.parent.find_or_declare(out))+ try:+ self.compiled_tasks.append(task)+ except AttributeError:+ self.compiled_tasks = [task]+ return task++ if getattr(self, 'generate_headers', None):+ tsk = create_compiled_task(self, 'd_with_header', node)+ tsk.outputs.append(node.change_ext(self.env['DHEADER_ext']))+ else:+ tsk = create_compiled_task(self, 'd', node)+ return tsk++@taskgen_method+def generate_header(self, filename):+ """+ See feature request #104::++ def build(bld):+ tg = bld.program(source='foo.d', target='app')+ tg.generate_header('blah.d')+ # is equivalent to:+ #tg = bld.program(source='foo.d', target='app', header_lst='blah.d')++ :param filename: header to create+ :type filename: string+ """+ try:+ self.header_lst.append([filename, self.install_path])+ except AttributeError:+ self.header_lst = [[filename, self.install_path]]++@feature('d')+def process_header(self):+ """+ Process the attribute 'header_lst' to create the d header compilation tasks::++ def build(bld):+ bld.program(source='foo.d', target='app', header_lst='blah.d')+ """+ for i in getattr(self, 'header_lst', []):+ node = self.path.find_resource(i[0])+ if not node:+ raise Errors.WafError('file %r not found on d obj' % i[0])+ self.create_task('d_header', node, node.change_ext('.di'))+new file mode 100644@@ -0,0 +1,63 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010 (ita)++from waflib import Utils+from waflib.Configure import conf++@conf+def d_platform_flags(self):+ """+ Set the extensions dll/so for d programs and libraries+ """+ v = self.env+ if not v.DEST_OS:+ v.DEST_OS = Utils.unversioned_sys_platform()+ binfmt = Utils.destos_to_binfmt(self.env.DEST_OS)+ if binfmt == 'pe':+ v['dprogram_PATTERN'] = '%s.exe'+ v['dshlib_PATTERN'] = 'lib%s.dll'+ v['dstlib_PATTERN'] = 'lib%s.a'+ elif binfmt == 'mac-o':+ v['dprogram_PATTERN'] = '%s'+ v['dshlib_PATTERN'] = 'lib%s.dylib'+ v['dstlib_PATTERN'] = 'lib%s.a'+ else:+ v['dprogram_PATTERN'] = '%s'+ v['dshlib_PATTERN'] = 'lib%s.so'+ v['dstlib_PATTERN'] = 'lib%s.a'++DLIB = '''+version(D_Version2) {+ import std.stdio;+ int main() {+ writefln("phobos2");+ return 0;+ }+} else {+ version(Tango) {+ import tango.stdc.stdio;+ int main() {+ printf("tango");+ return 0;+ }+ } else {+ import std.stdio;+ int main() {+ writefln("phobos1");+ return 0;+ }+ }+}+'''+"""Detection string for the D standard library"""++@conf+def check_dlibrary(self, execute=True):+ """+ Detect the kind of standard library that comes with the compiler, will set conf.env.DLIBRARY to tango, phobos1 or phobos2.+ """+ ret = self.check_cc(features='d dprogram', fragment=DLIB, compile_filename='test.d', execute=execute, define_ret=True)+ if execute:+ self.env.DLIBRARY = ret.strip()+new file mode 100644@@ -0,0 +1,209 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010 (ita)++"""+Provide a scanner for finding dependencies on d files+"""++import re+from waflib import Utils, Logs++def filter_comments(filename):+ """+ :param filename: d file name+ :type filename: string+ :rtype: list+ :return: a list of characters+ """+ txt = Utils.readf(filename)+ i = 0+ buf = []+ max = len(txt)+ begin = 0+ while i < max:+ c = txt[i]+ if c == '"' or c == "'": # skip a string or character literal+ buf.append(txt[begin:i])+ delim = c+ i += 1+ while i < max:+ c = txt[i]+ if c == delim: break+ elif c == '\\': # skip the character following backslash+ i += 1+ i += 1+ i += 1+ begin = i+ elif c == '/': # try to replace a comment with whitespace+ buf.append(txt[begin:i])+ i += 1+ if i == max: break+ c = txt[i]+ if c == '+': # eat nesting /+ +/ comment+ i += 1+ nesting = 1+ c = None+ while i < max:+ prev = c+ c = txt[i]+ if prev == '/' and c == '+':+ nesting += 1+ c = None+ elif prev == '+' and c == '/':+ nesting -= 1+ if nesting == 0: break+ c = None+ i += 1+ elif c == '*': # eat /* */ comment+ i += 1+ c = None+ while i < max:+ prev = c+ c = txt[i]+ if prev == '*' and c == '/': break+ i += 1+ elif c == '/': # eat // comment+ i += 1+ while i < max and txt[i] != '\n':+ i += 1+ else: # no comment+ begin = i - 1+ continue+ i += 1+ begin = i+ buf.append(' ')+ else:+ i += 1+ buf.append(txt[begin:])+ return buf++class d_parser(object):+ """+ Parser for d files+ """+ def __init__(self, env, incpaths):+ #self.code = ''+ #self.module = ''+ #self.imports = []++ self.allnames = []++ self.re_module = re.compile("module\s+([^;]+)")+ self.re_import = re.compile("import\s+([^;]+)")+ self.re_import_bindings = re.compile("([^:]+):(.*)")+ self.re_import_alias = re.compile("[^=]+=(.+)")++ self.env = env++ self.nodes = []+ self.names = []++ self.incpaths = incpaths++ def tryfind(self, filename):+ """+ Search file a file matching an module/import directive++ :param filename: file to read+ :type filename: string+ """+ found = 0+ for n in self.incpaths:+ found = n.find_resource(filename.replace('.', '/') + '.d')+ if found:+ self.nodes.append(found)+ self.waiting.append(found)+ break+ if not found:+ if not filename in self.names:+ self.names.append(filename)++ def get_strings(self, code):+ """+ :param code: d code to parse+ :type code: string+ :return: the modules that the code uses+ :rtype: a list of match objects+ """+ #self.imports = []+ self.module = ''+ lst = []++ # get the module name (if present)++ mod_name = self.re_module.search(code)+ if mod_name:+ self.module = re.sub('\s+', '', mod_name.group(1)) # strip all whitespaces++ # go through the code, have a look at all import occurrences++ # first, lets look at anything beginning with "import" and ending with ";"+ import_iterator = self.re_import.finditer(code)+ if import_iterator:+ for import_match in import_iterator:+ import_match_str = re.sub('\s+', '', import_match.group(1)) # strip all whitespaces++ # does this end with an import bindings declaration?+ # (import bindings always terminate the list of imports)+ bindings_match = self.re_import_bindings.match(import_match_str)+ if bindings_match:+ import_match_str = bindings_match.group(1)+ # if so, extract the part before the ":" (since the module declaration(s) is/are located there)++ # split the matching string into a bunch of strings, separated by a comma+ matches = import_match_str.split(',')++ for match in matches:+ alias_match = self.re_import_alias.match(match)+ if alias_match:+ # is this an alias declaration? (alias = module name) if so, extract the module name+ match = alias_match.group(1)++ lst.append(match)+ return lst++ def start(self, node):+ """+ The parsing starts here++ :param node: input file+ :type node: :py:class:`waflib.Node.Node`+ """+ self.waiting = [node]+ # while the stack is not empty, add the dependencies+ while self.waiting:+ nd = self.waiting.pop(0)+ self.iter(nd)++ def iter(self, node):+ """+ Find all the modules that a file depends on, uses :py:meth:`waflib.Tools.d_scan.d_parser.tryfind` to process dependent files++ :param node: input file+ :type node: :py:class:`waflib.Node.Node`+ """+ path = node.abspath() # obtain the absolute path+ code = "".join(filter_comments(path)) # read the file and filter the comments+ names = self.get_strings(code) # obtain the import strings+ for x in names:+ # optimization+ if x in self.allnames: continue+ self.allnames.append(x)++ # for each name, see if it is like a node or not+ self.tryfind(x)++def scan(self):+ "look for .d/.di used by a d file"+ env = self.env+ gruik = d_parser(env, self.generator.includes_nodes)+ node = self.inputs[0]+ gruik.start(node)+ nodes = gruik.nodes+ names = gruik.names++ if Logs.verbose:+ Logs.debug('deps: deps for %s: %r; unresolved %r' % (str(node), nodes, names))+ return (nodes, names)+new file mode 100644@@ -0,0 +1,70 @@+#!/usr/bin/env python+# encoding: utf-8+# Ali Sabil, 2007++"""+Compile dbus files with **dbus-binding-tool**++Typical usage::++ def options(opt):+ opt.load('compiler_c dbus')+ def configure(conf):+ conf.load('compiler_c dbus')+ def build(bld):+ tg = bld.program(+ includes = '.',+ source = bld.path.ant_glob('*.c'),+ target = 'gnome-hello')+ tg.add_dbus_file('test.xml', 'test_prefix', 'glib-server')+"""++from waflib import Task, Errors+from waflib.TaskGen import taskgen_method, before_method++@taskgen_method+def add_dbus_file(self, filename, prefix, mode):+ """+ Add a dbus file to the list of dbus files to process. Store them in the attribute *dbus_lst*.++ :param filename: xml file to compile+ :type filename: string+ :param prefix: dbus binding tool prefix (--prefix=prefix)+ :type prefix: string+ :param mode: dbus binding tool mode (--mode=mode)+ :type mode: string+ """+ if not hasattr(self, 'dbus_lst'):+ self.dbus_lst = []+ if not 'process_dbus' in self.meths:+ self.meths.append('process_dbus')+ self.dbus_lst.append([filename, prefix, mode])++@before_method('apply_core')+def process_dbus(self):+ """+ Process the dbus files stored in the attribute *dbus_lst* to create :py:class:`waflib.Tools.dbus.dbus_binding_tool` instances.+ """+ for filename, prefix, mode in getattr(self, 'dbus_lst', []):+ node = self.path.find_resource(filename)+ if not node:+ raise Errors.WafError('file not found ' + filename)+ tsk = self.create_task('dbus_binding_tool', node, node.change_ext('.h'))+ tsk.env.DBUS_BINDING_TOOL_PREFIX = prefix+ tsk.env.DBUS_BINDING_TOOL_MODE = mode++class dbus_binding_tool(Task.Task):+ """+ Compile a dbus file+ """+ color = 'BLUE'+ ext_out = ['.h']+ run_str = '${DBUS_BINDING_TOOL} --prefix=${DBUS_BINDING_TOOL_PREFIX} --mode=${DBUS_BINDING_TOOL_MODE} --output=${TGT} ${SRC}'+ shell = True # temporary workaround for #795++def configure(conf):+ """+ Detect the program dbus-binding-tool and set the *conf.env.DBUS_BINDING_TOOL*+ """+ dbus_binding_tool = conf.find_program('dbus-binding-tool', var='DBUS_BINDING_TOOL')+new file mode 100644@@ -0,0 +1,88 @@+#!/usr/bin/env python+# encoding: utf-8+# Carlos Rafael Giani, 2007 (dv)+# Thomas Nagy, 2008-2010 (ita)++import sys+from waflib.Tools import ar, d+from waflib.Configure import conf++@conf+def find_dmd(conf):+ """+ Find the program *dmd*, *dmd2*, or *ldc* and set the variable *D*+ """+ conf.find_program(['dmd', 'dmd2', 'ldc'], var='D')++ # make sure that we're dealing with dmd1, dmd2, or ldc(1)+ out = conf.cmd_and_log([conf.env.D, '--help'])+ if out.find("D Compiler v") == -1:+ out = conf.cmd_and_log([conf.env.D, '-version'])+ if out.find("based on DMD v1.") == -1:+ conf.fatal("detected compiler is not dmd/ldc")++@conf+def common_flags_ldc(conf):+ """+ Set the D flags required by *ldc*+ """+ v = conf.env+ v['DFLAGS'] = ['-d-version=Posix']+ v['LINKFLAGS'] = []+ v['DFLAGS_dshlib'] = ['-relocation-model=pic']++@conf+def common_flags_dmd(conf):+ """+ Set the flags required by *dmd* or *dmd2*+ """++ v = conf.env++ # _DFLAGS _DIMPORTFLAGS++ # Compiler is dmd so 'gdc' part will be ignored, just+ # ensure key is there, so wscript can append flags to it+ #v['DFLAGS'] = ['-version=Posix']++ v['D_SRC_F'] = ['-c']+ v['D_TGT_F'] = '-of%s'++ # linker+ v['D_LINKER'] = v['D']+ v['DLNK_SRC_F'] = ''+ v['DLNK_TGT_F'] = '-of%s'+ v['DINC_ST'] = '-I%s'++ v['DSHLIB_MARKER'] = v['DSTLIB_MARKER'] = ''+ v['DSTLIB_ST'] = v['DSHLIB_ST'] = '-L-l%s'+ v['DSTLIBPATH_ST'] = v['DLIBPATH_ST'] = '-L-L%s'++ v['LINKFLAGS_dprogram']= ['-quiet']++ v['DFLAGS_dshlib'] = ['-fPIC']+ v['LINKFLAGS_dshlib'] = ['-L-shared']++ v['DHEADER_ext'] = '.di'+ v.DFLAGS_d_with_header = ['-H', '-Hf']+ v['D_HDR_F'] = '%s'++def configure(conf):+ """+ Configuration for *dmd*, *dmd2*, and *ldc*+ """+ conf.find_dmd()++ if sys.platform == 'win32':+ out = conf.cmd_and_log([conf.env.D, '--help'])+ if out.find("D Compiler v2.") > -1:+ conf.fatal('dmd2 on Windows is not supported, use gdc or ldc2 instead')++ conf.load('ar')+ conf.load('d')+ conf.common_flags_dmd()+ conf.d_platform_flags()++ if str(conf.env.D).find('ldc') > -1:+ conf.common_flags_ldc()+new file mode 100644@@ -0,0 +1,220 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2011 (ita)++"""+errcheck: highlight common mistakes++There is a performance hit, so this tool is only loaded when running "waf -v"+"""++typos = {+'feature':'features',+'sources':'source',+'targets':'target',+'include':'includes',+'export_include':'export_includes',+'define':'defines',+'importpath':'includes',+'installpath':'install_path',+'iscopy':'is_copy',+}++meths_typos = ['__call__', 'program', 'shlib', 'stlib', 'objects']++from waflib import Logs, Build, Node, Task, TaskGen, ConfigSet, Errors, Utils+import waflib.Tools.ccroot++def check_same_targets(self):+ mp = Utils.defaultdict(list)+ uids = {}++ def check_task(tsk):+ if not isinstance(tsk, Task.Task):+ return++ for node in tsk.outputs:+ mp[node].append(tsk)+ try:+ uids[tsk.uid()].append(tsk)+ except KeyError:+ uids[tsk.uid()] = [tsk]++ for g in self.groups:+ for tg in g:+ try:+ for tsk in tg.tasks:+ check_task(tsk)+ except AttributeError:+ # raised if not a task generator, which should be uncommon+ check_task(tg)++ dupe = False+ for (k, v) in mp.items():+ if len(v) > 1:+ dupe = True+ msg = '* Node %r is created more than once%s. The task generators are:' % (k, Logs.verbose == 1 and " (full message on 'waf -v -v')" or "")+ Logs.error(msg)+ for x in v:+ if Logs.verbose > 1:+ Logs.error(' %d. %r' % (1 + v.index(x), x.generator))+ else:+ Logs.error(' %d. %r in %r' % (1 + v.index(x), x.generator.name, getattr(x.generator, 'path', None)))++ if not dupe:+ for (k, v) in uids.items():+ if len(v) > 1:+ Logs.error('* Several tasks use the same identifier. Please check the information on\n http://docs.waf.googlecode.com/git/apidocs_16/Task.html#waflib.Task.Task.uid')+ for tsk in v:+ Logs.error(' - object %r (%r) defined in %r' % (tsk.__class__.__name__, tsk, tsk.generator))++def check_invalid_constraints(self):+ feat = set([])+ for x in list(TaskGen.feats.values()):+ feat.union(set(x))+ for (x, y) in TaskGen.task_gen.prec.items():+ feat.add(x)+ feat.union(set(y))+ ext = set([])+ for x in TaskGen.task_gen.mappings.values():+ ext.add(x.__name__)+ invalid = ext & feat+ if invalid:+ Logs.error('The methods %r have invalid annotations: @extension <-> @feature/@before_method/@after_method' % list(invalid))++ # the build scripts have been read, so we can check for invalid after/before attributes on task classes+ for cls in list(Task.classes.values()):+ for x in ('before', 'after'):+ for y in Utils.to_list(getattr(cls, x, [])):+ if not Task.classes.get(y, None):+ Logs.error('Erroneous order constraint %r=%r on task class %r' % (x, y, cls.__name__))+ if getattr(cls, 'rule', None):+ Logs.error('Erroneous attribute "rule" on task class %r (rename to "run_str")' % cls.__name__)++def replace(m):+ """+ We could add properties, but they would not work in some cases:+ bld.program(...) requires 'source' in the attributes+ """+ oldcall = getattr(Build.BuildContext, m)+ def call(self, *k, **kw):+ ret = oldcall(self, *k, **kw)+ for x in typos:+ if x in kw:+ if x == 'iscopy' and 'subst' in getattr(self, 'features', ''):+ continue+ err = True+ Logs.error('Fix the typo %r -> %r on %r' % (x, typos[x], ret))+ return ret+ setattr(Build.BuildContext, m, call)++def enhance_lib():+ """+ modify existing classes and methods+ """+ for m in meths_typos:+ replace(m)++ # catch '..' in ant_glob patterns+ def ant_glob(self, *k, **kw):+ if k:+ lst=Utils.to_list(k[0])+ for pat in lst:+ if '..' in pat.split('/'):+ Logs.error("In ant_glob pattern %r: '..' means 'two dots', not 'parent directory'" % k[0])+ if kw.get('remove', True):+ try:+ if self.is_child_of(self.ctx.bldnode) and not kw.get('quiet', False):+ Logs.error('Using ant_glob on the build folder (%r) is dangerous (quiet=True to disable this warning)' % self)+ except AttributeError:+ pass+ return self.old_ant_glob(*k, **kw)+ Node.Node.old_ant_glob = Node.Node.ant_glob+ Node.Node.ant_glob = ant_glob++ # catch conflicting ext_in/ext_out/before/after declarations+ old = Task.is_before+ def is_before(t1, t2):+ ret = old(t1, t2)+ if ret and old(t2, t1):+ Logs.error('Contradictory order constraints in classes %r %r' % (t1, t2))+ return ret+ Task.is_before = is_before++ # check for bld(feature='cshlib') where no 'c' is given - this can be either a mistake or on purpose+ # so we only issue a warning+ def check_err_features(self):+ lst = self.to_list(self.features)+ if 'shlib' in lst:+ Logs.error('feature shlib -> cshlib, dshlib or cxxshlib')+ for x in ('c', 'cxx', 'd', 'fc'):+ if not x in lst and lst and lst[0] in [x+y for y in ('program', 'shlib', 'stlib')]:+ Logs.error('%r features is probably missing %r' % (self, x))+ TaskGen.feature('*')(check_err_features)++ # check for erroneous order constraints+ def check_err_order(self):+ if not hasattr(self, 'rule') and not 'subst' in Utils.to_list(self.features):+ for x in ('before', 'after', 'ext_in', 'ext_out'):+ if hasattr(self, x):+ Logs.warn('Erroneous order constraint %r on non-rule based task generator %r' % (x, self))+ else:+ for x in ('before', 'after'):+ for y in self.to_list(getattr(self, x, [])):+ if not Task.classes.get(y, None):+ Logs.error('Erroneous order constraint %s=%r on %r (no such class)' % (x, y, self))+ TaskGen.feature('*')(check_err_order)++ # check for @extension used with @feature/@before_method/@after_method+ def check_compile(self):+ check_invalid_constraints(self)+ try:+ ret = self.orig_compile()+ finally:+ check_same_targets(self)+ return ret+ Build.BuildContext.orig_compile = Build.BuildContext.compile+ Build.BuildContext.compile = check_compile++ # check for invalid build groups #914+ def use_rec(self, name, **kw):+ try:+ y = self.bld.get_tgen_by_name(name)+ except Errors.WafError:+ pass+ else:+ idx = self.bld.get_group_idx(self)+ odx = self.bld.get_group_idx(y)+ if odx > idx:+ msg = "Invalid 'use' across build groups:"+ if Logs.verbose > 1:+ msg += '\n target %r\n uses:\n %r' % (self, y)+ else:+ msg += " %r uses %r (try 'waf -v -v' for the full error)" % (self.name, name)+ raise Errors.WafError(msg)+ self.orig_use_rec(name, **kw)+ TaskGen.task_gen.orig_use_rec = TaskGen.task_gen.use_rec+ TaskGen.task_gen.use_rec = use_rec++ # check for env.append+ def getattri(self, name, default=None):+ if name == 'append' or name == 'add':+ raise Errors.WafError('env.append and env.add do not exist: use env.append_value/env.append_unique')+ elif name == 'prepend':+ raise Errors.WafError('env.prepend does not exist: use env.prepend_value')+ if name in self.__slots__:+ return object.__getattr__(self, name, default)+ else:+ return self[name]+ ConfigSet.ConfigSet.__getattr__ = getattri+++def options(opt):+ """+ Add a few methods+ """+ enhance_lib()++def configure(conf):+ pass+new file mode 100644@@ -0,0 +1,199 @@+#! /usr/bin/env python+# encoding: utf-8+# DC 2008+# Thomas Nagy 2010 (ita)++"""+fortran support+"""++import re++from waflib import Utils, Task, TaskGen, Logs+from waflib.Tools import ccroot, fc_config, fc_scan+from waflib.TaskGen import feature, before_method, after_method, extension+from waflib.Configure import conf++ccroot.USELIB_VARS['fc'] = set(['FCFLAGS', 'DEFINES', 'INCLUDES'])+ccroot.USELIB_VARS['fcprogram_test'] = ccroot.USELIB_VARS['fcprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])+ccroot.USELIB_VARS['fcshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS'])+ccroot.USELIB_VARS['fcstlib'] = set(['ARFLAGS', 'LINKDEPS'])++@feature('fcprogram', 'fcshlib', 'fcstlib', 'fcprogram_test')+def dummy(self):+ pass++@extension('.f', '.f90', '.F', '.F90', '.for', '.FOR')+def fc_hook(self, node):+ "Bind the typical Fortran file extensions to the creation of a :py:class:`waflib.Tools.fc.fc` instance"+ return self.create_compiled_task('fc', node)++@conf+def modfile(conf, name):+ """+ Turn a module name into the right module file name.+ Defaults to all lower case.+ """+ return {'lower' :name.lower() + '.mod',+ 'lower.MOD' :name.upper() + '.MOD',+ 'UPPER.mod' :name.upper() + '.mod',+ 'UPPER' :name.upper() + '.MOD'}[conf.env.FC_MOD_CAPITALIZATION or 'lower']++def get_fortran_tasks(tsk):+ """+ Obtain all other fortran tasks from the same build group. Those tasks must not have+ the attribute 'nomod' or 'mod_fortran_done'+ """+ bld = tsk.generator.bld+ tasks = bld.get_tasks_group(bld.get_group_idx(tsk.generator))+ return [x for x in tasks if isinstance(x, fc) and not getattr(x, 'nomod', None) and not getattr(x, 'mod_fortran_done', None)]++class fc(Task.Task):+ """+ The fortran tasks can only run when all fortran tasks in the current group are ready to be executed+ This may cause a deadlock if another fortran task is waiting for something that cannot happen (circular dependency)+ in this case, set the 'nomod=True' on those tasks instances to break the loop+ """++ color = 'GREEN'+ run_str = '${FC} ${FCFLAGS} ${FCINCPATH_ST:INCPATHS} ${FCDEFINES_ST:DEFINES} ${_FCMODOUTFLAGS} ${FC_TGT_F}${TGT[0].abspath()} ${FC_SRC_F}${SRC[0].abspath()}'+ vars = ["FORTRANMODPATHFLAG"]++ def scan(self):+ """scanner for fortran dependencies"""+ tmp = fc_scan.fortran_parser(self.generator.includes_nodes)+ tmp.task = self+ tmp.start(self.inputs[0])+ if Logs.verbose:+ Logs.debug('deps: deps for %r: %r; unresolved %r' % (self.inputs, tmp.nodes, tmp.names))+ return (tmp.nodes, tmp.names)++ def runnable_status(self):+ """+ Set the mod file outputs and the dependencies on the mod files over all the fortran tasks+ executed by the main thread so there are no concurrency issues+ """+ if getattr(self, 'mod_fortran_done', None):+ return super(fc, self).runnable_status()++ # now, if we reach this part it is because this fortran task is the first in the list+ bld = self.generator.bld++ # obtain the fortran tasks+ lst = get_fortran_tasks(self)++ # disable this method for other tasks+ for tsk in lst:+ tsk.mod_fortran_done = True++ # wait for all the .f tasks to be ready for execution+ # and ensure that the scanners are called at least once+ for tsk in lst:+ ret = tsk.runnable_status()+ if ret == Task.ASK_LATER:+ # we have to wait for one of the other fortran tasks to be ready+ # this may deadlock if there are dependencies between the fortran tasks+ # but this should not happen (we are setting them here!)+ for x in lst:+ x.mod_fortran_done = None++ # TODO sort the list of tasks in bld.producer.outstanding to put all fortran tasks at the end+ return Task.ASK_LATER++ ins = Utils.defaultdict(set)+ outs = Utils.defaultdict(set)++ # the .mod files to create+ for tsk in lst:+ key = tsk.uid()+ for x in bld.raw_deps[key]:+ if x.startswith('MOD@'):+ name = bld.modfile(x.replace('MOD@', ''))+ node = bld.srcnode.find_or_declare(name)+ tsk.set_outputs(node)+ outs[id(node)].add(tsk)++ # the .mod files to use+ for tsk in lst:+ key = tsk.uid()+ for x in bld.raw_deps[key]:+ if x.startswith('USE@'):+ name = bld.modfile(x.replace('USE@', ''))+ node = bld.srcnode.find_resource(name)+ if node and node not in tsk.outputs:+ if not node in bld.node_deps[key]:+ bld.node_deps[key].append(node)+ ins[id(node)].add(tsk)++ # if the intersection matches, set the order+ for k in ins.keys():+ for a in ins[k]:+ a.run_after.update(outs[k])++ # the scanner cannot output nodes, so we have to set them+ # ourselves as task.dep_nodes (additional input nodes)+ tmp = []+ for t in outs[k]:+ tmp.extend(t.outputs)+ a.dep_nodes.extend(tmp)+ a.dep_nodes.sort(key=lambda x: x.abspath())++ # the task objects have changed: clear the signature cache+ for tsk in lst:+ try:+ delattr(tsk, 'cache_sig')+ except AttributeError:+ pass++ return super(fc, self).runnable_status()++class fcprogram(ccroot.link_task):+ """Link fortran programs"""+ color = 'YELLOW'+ run_str = '${FC} ${LINKFLAGS} ${FCLNK_SRC_F}${SRC} ${FCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FCSTLIB_MARKER} ${FCSTLIBPATH_ST:STLIBPATH} ${FCSTLIB_ST:STLIB} ${FCSHLIB_MARKER} ${FCLIBPATH_ST:LIBPATH} ${FCLIB_ST:LIB}'+ inst_to = '${BINDIR}'++class fcshlib(fcprogram):+ """Link fortran libraries"""+ inst_to = '${LIBDIR}'++class fcprogram_test(fcprogram):+ """Custom link task to obtain the compiler outputs for fortran configuration tests"""++ def can_retrieve_cache(self):+ """This task is always executed"""+ return False++ def runnable_status(self):+ """This task is always executed"""+ ret = super(fcprogram_test, self).runnable_status()+ if ret == Task.SKIP_ME:+ ret = Task.RUN_ME+ return ret++ def exec_command(self, cmd, **kw):+ """Store the compiler std our/err onto the build context, to bld.out + bld.err"""+ bld = self.generator.bld++ kw['shell'] = isinstance(cmd, str)+ kw['stdout'] = kw['stderr'] = Utils.subprocess.PIPE+ kw['cwd'] = bld.variant_dir+ bld.out = bld.err = ''++ bld.to_log('command: %s\n' % cmd)++ kw['output'] = 0+ try:+ (bld.out, bld.err) = bld.cmd_and_log(cmd, **kw)+ except Exception as e:+ return -1++ if bld.out:+ bld.to_log("out: %s\n" % bld.out)+ if bld.err:+ bld.to_log("err: %s\n" % bld.err)++class fcstlib(ccroot.stlink_task):+ """Link fortran static libraries (uses ar by default)"""+ pass # do not remove the pass statement+new file mode 100644@@ -0,0 +1,468 @@+#! /usr/bin/env python+# encoding: utf-8+# DC 2008+# Thomas Nagy 2010 (ita)++"""+Fortran configuration helpers+"""++import re, shutil, os, sys, string, shlex+from waflib.Configure import conf+from waflib.TaskGen import feature, after_method, before_method+from waflib import Build, Utils++FC_FRAGMENT = ' program main\n end program main\n'+FC_FRAGMENT2 = ' PROGRAM MAIN\n END\n' # what's the actual difference between these?++@conf+def fc_flags(conf):+ """+ Define common fortran configuration flags and file extensions+ """+ v = conf.env++ v['FC_SRC_F'] = []+ v['FC_TGT_F'] = ['-c', '-o']+ v['FCINCPATH_ST'] = '-I%s'+ v['FCDEFINES_ST'] = '-D%s'++ if not v['LINK_FC']: v['LINK_FC'] = v['FC']+ v['FCLNK_SRC_F'] = []+ v['FCLNK_TGT_F'] = ['-o']++ v['FCFLAGS_fcshlib'] = ['-fpic']+ v['LINKFLAGS_fcshlib'] = ['-shared']+ v['fcshlib_PATTERN'] = 'lib%s.so'++ v['fcstlib_PATTERN'] = 'lib%s.a'++ v['FCLIB_ST'] = '-l%s'+ v['FCLIBPATH_ST'] = '-L%s'+ v['FCSTLIB_ST'] = '-l%s'+ v['FCSTLIBPATH_ST'] = '-L%s'+ v['FCSTLIB_MARKER'] = '-Wl,-Bstatic'+ v['FCSHLIB_MARKER'] = '-Wl,-Bdynamic'++ v['SONAME_ST'] = '-Wl,-h,%s'++@conf+def fc_add_flags(conf):+ """+ FCFLAGS?+ """+ conf.add_os_flags('FCFLAGS')+ conf.add_os_flags('LDFLAGS', 'LINKFLAGS')++@conf+def check_fortran(self, *k, **kw):+ """See if the fortran compiler works by compiling a simple fortran program"""+ self.check_cc(+ fragment = FC_FRAGMENT,+ compile_filename = 'test.f',+ features = 'fc fcprogram',+ msg = 'Compiling a simple fortran app')++@conf+def check_fc(self, *k, **kw):+ """+ Same as :py:func:`waflib.Tools.c_config.check` but default to the *Fortran* programming language+ (Overriding the C defaults in :py:func:`waflib.Tools.c_config.validate_c` here)+ """+ kw['compiler'] = 'fc'+ if not 'compile_mode' in kw:+ kw['compile_mode'] = 'fc'+ if not 'type' in kw:+ kw['type'] = 'fcprogram'+ if not 'compile_filename' in kw:+ kw['compile_filename'] = 'test.f90'+ if not 'code' in kw:+ kw['code'] = FC_FRAGMENT+ return self.check(*k, **kw)++# ------------------------------------------------------------------------+# --- These are the default platform modifiers, refactored here for+# convenience. gfortran and g95 have much overlap.+# ------------------------------------------------------------------------++@conf+def fortran_modifier_darwin(conf):+ """+ Define fortran flags and extensions for the OSX systems+ """+ v = conf.env+ v['FCFLAGS_fcshlib'] = ['-fPIC', '-compatibility_version', '1', '-current_version', '1']+ v['LINKFLAGS_fcshlib'] = ['-dynamiclib']+ v['fcshlib_PATTERN'] = 'lib%s.dylib'+ v['FRAMEWORKPATH_ST'] = '-F%s'+ v['FRAMEWORK_ST'] = '-framework %s'++ v['LINKFLAGS_fcstlib'] = []++ v['FCSHLIB_MARKER'] = ''+ v['FCSTLIB_MARKER'] = ''+ v['SONAME_ST'] = ''+++@conf+def fortran_modifier_win32(conf):+ """Define fortran flags for the windows platforms"""+ v = conf.env+ v['fcprogram_PATTERN'] = v['fcprogram_test_PATTERN'] = '%s.exe'++ v['fcshlib_PATTERN'] = '%s.dll'+ v['implib_PATTERN'] = 'lib%s.dll.a'+ v['IMPLIB_ST'] = '-Wl,--out-implib,%s'++ v['FCFLAGS_fcshlib'] = []++ v.append_value('FCFLAGS_fcshlib', ['-DDLL_EXPORT']) # TODO adding nonstandard defines like this DLL_EXPORT is not a good idea++ # Auto-import is enabled by default even without this option,+ # but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages+ # that the linker emits otherwise.+ v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import'])++@conf+def fortran_modifier_cygwin(conf):+ """Define fortran flags for use on cygwin"""+ fortran_modifier_win32(conf)+ v = conf.env+ v['fcshlib_PATTERN'] = 'cyg%s.dll'+ v.append_value('LINKFLAGS_fcshlib', ['-Wl,--enable-auto-image-base'])+ v['FCFLAGS_fcshlib'] = []+# ------------------------------------------------------------------------++@conf+def check_fortran_dummy_main(self, *k, **kw):+ """+ Guess if a main function is needed by compiling a code snippet with+ the C compiler and link with the Fortran compiler++ TODO: (DC)+ - handling dialects (F77, F90, etc... -> needs core support first)+ - fix dummy main check (AC_FC_DUMMY_MAIN vs AC_FC_MAIN)++ TODO: what does the above mean? (ita)+ """++ if not self.env.CC:+ self.fatal('A c compiler is required for check_fortran_dummy_main')++ lst = ['MAIN__', '__MAIN', '_MAIN', 'MAIN_', 'MAIN']+ lst.extend([m.lower() for m in lst])+ lst.append('')++ self.start_msg('Detecting whether we need a dummy main')+ for main in lst:+ kw['fortran_main'] = main+ try:+ self.check_cc(+ fragment = 'int %s() { return 0; }\n' % (main or 'test'),+ features = 'c fcprogram',+ mandatory = True+ )+ if not main:+ self.env.FC_MAIN = -1+ self.end_msg('no')+ else:+ self.env.FC_MAIN = main+ self.end_msg('yes %s' % main)+ break+ except self.errors.ConfigurationError:+ pass+ else:+ self.end_msg('not found')+ self.fatal('could not detect whether fortran requires a dummy main, see the config.log')++# ------------------------------------------------------------------------++GCC_DRIVER_LINE = re.compile('^Driving:')+POSIX_STATIC_EXT = re.compile('\S+\.a')+POSIX_LIB_FLAGS = re.compile('-l\S+')++@conf+def is_link_verbose(self, txt):+ """Return True if 'useful' link options can be found in txt"""+ assert isinstance(txt, str)+ for line in txt.splitlines():+ if not GCC_DRIVER_LINE.search(line):+ if POSIX_STATIC_EXT.search(line) or POSIX_LIB_FLAGS.search(line):+ return True+ return False++@conf+def check_fortran_verbose_flag(self, *k, **kw):+ """+ Check what kind of verbose (-v) flag works, then set it to env.FC_VERBOSE_FLAG+ """+ self.start_msg('fortran link verbose flag')+ for x in ['-v', '--verbose', '-verbose', '-V']:+ try:+ self.check_cc(+ features = 'fc fcprogram_test',+ fragment = FC_FRAGMENT2,+ compile_filename = 'test.f',+ linkflags = [x],+ mandatory=True+ )+ except self.errors.ConfigurationError:+ pass+ else:+ # output is on stderr or stdout (for xlf)+ if self.is_link_verbose(self.test_bld.err) or self.is_link_verbose(self.test_bld.out):+ self.end_msg(x)+ break+ else:+ self.end_msg('failure')+ self.fatal('Could not obtain the fortran link verbose flag (see config.log)')++ self.env.FC_VERBOSE_FLAG = x+ return x++# ------------------------------------------------------------------------++# linkflags which match those are ignored+LINKFLAGS_IGNORED = [r'-lang*', r'-lcrt[a-zA-Z0-9\.]*\.o', r'-lc$', r'-lSystem', r'-libmil', r'-LIST:*', r'-LNO:*']+if os.name == 'nt':+ LINKFLAGS_IGNORED.extend([r'-lfrt*', r'-luser32', r'-lkernel32', r'-ladvapi32', r'-lmsvcrt', r'-lshell32', r'-lmingw', r'-lmoldname'])+else:+ LINKFLAGS_IGNORED.append(r'-lgcc*')+RLINKFLAGS_IGNORED = [re.compile(f) for f in LINKFLAGS_IGNORED]++def _match_ignore(line):+ """Returns True if the line should be ignored (fortran test for verbosity)."""+ for i in RLINKFLAGS_IGNORED:+ if i.match(line):+ return True+ return False++def parse_fortran_link(lines):+ """Given the output of verbose link of Fortran compiler, this returns a+ list of flags necessary for linking using the standard linker."""+ # TODO: On windows ?+ final_flags = []+ for line in lines:+ if not GCC_DRIVER_LINE.match(line):+ _parse_flink_line(line, final_flags)+ return final_flags++SPACE_OPTS = re.compile('^-[LRuYz]$')+NOSPACE_OPTS = re.compile('^-[RL]')++def _parse_flink_line(line, final_flags):+ """private"""+ lexer = shlex.shlex(line, posix = True)+ lexer.whitespace_split = True++ t = lexer.get_token()+ tmp_flags = []+ while t:+ def parse(token):+ # Here we go (convention for wildcard is shell, not regex !)+ # 1 TODO: we first get some root .a libraries+ # 2 TODO: take everything starting by -bI:*+ # 3 Ignore the following flags: -lang* | -lcrt*.o | -lc |+ # -lgcc* | -lSystem | -libmil | -LANG:=* | -LIST:* | -LNO:*)+ # 4 take into account -lkernel32+ # 5 For options of the kind -[[LRuYz]], as they take one argument+ # after, the actual option is the next token+ # 6 For -YP,*: take and replace by -Larg where arg is the old+ # argument+ # 7 For -[lLR]*: take++ # step 3+ if _match_ignore(token):+ pass+ # step 4+ elif token.startswith('-lkernel32') and sys.platform == 'cygwin':+ tmp_flags.append(token)+ # step 5+ elif SPACE_OPTS.match(token):+ t = lexer.get_token()+ if t.startswith('P,'):+ t = t[2:]+ for opt in t.split(os.pathsep):+ tmp_flags.append('-L%s' % opt)+ # step 6+ elif NOSPACE_OPTS.match(token):+ tmp_flags.append(token)+ # step 7+ elif POSIX_LIB_FLAGS.match(token):+ tmp_flags.append(token)+ else:+ # ignore anything not explicitely taken into account+ pass++ t = lexer.get_token()+ return t+ t = parse(t)++ final_flags.extend(tmp_flags)+ return final_flags++@conf+def check_fortran_clib(self, autoadd=True, *k, **kw):+ """+ Obtain the flags for linking with the C library+ if this check works, add uselib='CLIB' to your task generators+ """+ if not self.env.FC_VERBOSE_FLAG:+ self.fatal('env.FC_VERBOSE_FLAG is not set: execute check_fortran_verbose_flag?')++ self.start_msg('Getting fortran runtime link flags')+ try:+ self.check_cc(+ fragment = FC_FRAGMENT2,+ compile_filename = 'test.f',+ features = 'fc fcprogram_test',+ linkflags = [self.env.FC_VERBOSE_FLAG]+ )+ except Exception:+ self.end_msg(False)+ if kw.get('mandatory', True):+ conf.fatal('Could not find the c library flags')+ else:+ out = self.test_bld.err+ flags = parse_fortran_link(out.splitlines())+ self.end_msg('ok (%s)' % ' '.join(flags))+ self.env.LINKFLAGS_CLIB = flags+ return flags+ return []++def getoutput(conf, cmd, stdin=False):+ """+ TODO a bit redundant, can be removed anytime+ """+ if stdin:+ stdin = Utils.subprocess.PIPE+ else:+ stdin = None+ env = conf.env.env or None+ try:+ p = Utils.subprocess.Popen(cmd, stdin=stdin, stdout=Utils.subprocess.PIPE, stderr=Utils.subprocess.PIPE, env=env)+ if stdin:+ p.stdin.write('\n'.encode())+ out, err = p.communicate()+ except Exception:+ conf.fatal('could not determine the compiler version %r' % cmd)+ if not isinstance(out, str):+ out = out.decode(sys.stdout.encoding or 'iso8859-1')+ if not isinstance(err, str):+ err = err.decode(sys.stdout.encoding or 'iso8859-1')+ return (out, err)++# ------------------------------------------------------------------------++ROUTINES_CODE = """\+ subroutine foobar()+ return+ end+ subroutine foo_bar()+ return+ end+"""++MAIN_CODE = """+void %(dummy_func_nounder)s(void);+void %(dummy_func_under)s(void);+int %(main_func_name)s() {+ %(dummy_func_nounder)s();+ %(dummy_func_under)s();+ return 0;+}+"""++@feature('link_main_routines_func')+@before_method('process_source')+def link_main_routines_tg_method(self):+ """+ The configuration test declares a unique task generator,+ so we create other task generators from there for fortran link tests+ """+ def write_test_file(task):+ task.outputs[0].write(task.generator.code)+ bld = self.bld+ bld(rule=write_test_file, target='main.c', code=MAIN_CODE % self.__dict__)+ bld(rule=write_test_file, target='test.f', code=ROUTINES_CODE)+ bld(features='fc fcstlib', source='test.f', target='test')+ bld(features='c fcprogram', source='main.c', target='app', use='test')++def mangling_schemes():+ """+ Generate triplets for use with mangle_name+ (used in check_fortran_mangling)+ the order is tuned for gfortan+ """+ for u in ['_', '']:+ for du in ['', '_']:+ for c in ["lower", "upper"]:+ yield (u, du, c)++def mangle_name(u, du, c, name):+ """Mangle a name from a triplet (used in check_fortran_mangling)"""+ return getattr(name, c)() + u + (name.find('_') != -1 and du or '')++@conf+def check_fortran_mangling(self, *k, **kw):+ """+ Detect the mangling scheme, sets FORTRAN_MANGLING to the triplet found++ This test will compile a fortran static library, then link a c app against it+ """+ if not self.env.CC:+ self.fatal('A c compiler is required for link_main_routines')+ if not self.env.FC:+ self.fatal('A fortran compiler is required for link_main_routines')+ if not self.env.FC_MAIN:+ self.fatal('Checking for mangling requires self.env.FC_MAIN (execute "check_fortran_dummy_main" first?)')++ self.start_msg('Getting fortran mangling scheme')+ for (u, du, c) in mangling_schemes():+ try:+ self.check_cc(+ compile_filename = [],+ features = 'link_main_routines_func',+ msg = 'nomsg',+ errmsg = 'nomsg',+ mandatory=True,+ dummy_func_nounder = mangle_name(u, du, c, "foobar"),+ dummy_func_under = mangle_name(u, du, c, "foo_bar"),+ main_func_name = self.env.FC_MAIN+ )+ except self.errors.ConfigurationError:+ pass+ else:+ self.end_msg("ok ('%s', '%s', '%s-case')" % (u, du, c))+ self.env.FORTRAN_MANGLING = (u, du, c)+ break+ else:+ self.end_msg(False)+ self.fatal('mangler not found')++ return (u, du, c)++@feature('pyext')+@before_method('propagate_uselib_vars', 'apply_link')+def set_lib_pat(self):+ """Set the fortran flags for linking with the python library"""+ self.env['fcshlib_PATTERN'] = self.env['pyext_PATTERN']++@conf+def detect_openmp(self):+ for x in ['-fopenmp','-openmp','-mp','-xopenmp','-omp','-qsmp=omp']:+ try:+ self.check_fc(+ msg='Checking for OpenMP flag %s' % x,+ fragment='program main\n call omp_get_num_threads()\nend program main',+ fcflags=x,+ linkflags=x,+ uselib_store='OPENMP'+ )+ except self.errors.ConfigurationError:+ pass+ else:+ break+ else:+ self.fatal('Could not find OpenMP')+new file mode 100644@@ -0,0 +1,121 @@+#! /usr/bin/env python+# encoding: utf-8+# DC 2008+# Thomas Nagy 2010 (ita)++import re++from waflib import Utils, Task, TaskGen, Logs+from waflib.TaskGen import feature, before_method, after_method, extension+from waflib.Configure import conf++INC_REGEX = """(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""+USE_REGEX = """(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"""+MOD_REGEX = """(?:^|;)\s*MODULE(?!\s*PROCEDURE)(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"""++re_inc = re.compile(INC_REGEX, re.I)+re_use = re.compile(USE_REGEX, re.I)+re_mod = re.compile(MOD_REGEX, re.I)++class fortran_parser(object):+ """+ This parser will return:++ * the nodes corresponding to the module names that will be produced+ * the nodes corresponding to the include files used+ * the module names used by the fortran file+ """++ def __init__(self, incpaths):+ self.seen = []+ """Files already parsed"""++ self.nodes = []+ """List of :py:class:`waflib.Node.Node` representing the dependencies to return"""++ self.names = []+ """List of module names to return"""++ self.incpaths = incpaths+ """List of :py:class:`waflib.Node.Node` representing the include paths"""++ def find_deps(self, node):+ """+ Parse a fortran file to read the dependencies used and provided++ :param node: fortran file to read+ :type node: :py:class:`waflib.Node.Node`+ :return: lists representing the includes, the modules used, and the modules created by a fortran file+ :rtype: tuple of list of strings+ """+ txt = node.read()+ incs = []+ uses = []+ mods = []+ for line in txt.splitlines():+ # line by line regexp search? optimize?+ m = re_inc.search(line)+ if m:+ incs.append(m.group(1))+ m = re_use.search(line)+ if m:+ uses.append(m.group(1))+ m = re_mod.search(line)+ if m:+ mods.append(m.group(1))+ return (incs, uses, mods)++ def start(self, node):+ """+ Start the parsing. Use the stack self.waiting to hold the nodes to iterate on++ :param node: fortran file+ :type node: :py:class:`waflib.Node.Node`+ """+ self.waiting = [node]+ while self.waiting:+ nd = self.waiting.pop(0)+ self.iter(nd)++ def iter(self, node):+ """+ Process a single file in the search for dependencies, extract the files used+ the modules used, and the modules provided.+ """+ path = node.abspath()+ incs, uses, mods = self.find_deps(node)+ for x in incs:+ if x in self.seen:+ continue+ self.seen.append(x)+ self.tryfind_header(x)++ for x in uses:+ name = "USE@%s" % x+ if not name in self.names:+ self.names.append(name)++ for x in mods:+ name = "MOD@%s" % x+ if not name in self.names:+ self.names.append(name)++ def tryfind_header(self, filename):+ """+ Try to find an include and add it the nodes to process++ :param filename: file name+ :type filename: string+ """+ found = None+ for n in self.incpaths:+ found = n.find_resource(filename)+ if found:+ self.nodes.append(found)+ self.waiting.append(found)+ break+ if not found:+ if not filename in self.names:+ self.names.append(filename)++new file mode 100644@@ -0,0 +1,52 @@+#!/usr/bin/env python+# encoding: utf-8+# John O'Meara, 2006+# Thomas Nagy, 2006-2010 (ita)++"""+The **flex** program is a code generator which creates C or C++ files.+The generated files are compiled into object files.+"""++import waflib.TaskGen, os, re++def decide_ext(self, node):+ if 'cxx' in self.features:+ return ['.lex.cc']+ return ['.lex.c']++def flexfun(tsk):+ env = tsk.env+ bld = tsk.generator.bld+ wd = bld.variant_dir+ def to_list(xx):+ if isinstance(xx, str): return [xx]+ return xx+ tsk.last_cmd = lst = []+ lst.extend(to_list(env['FLEX']))+ lst.extend(to_list(env['FLEXFLAGS']))+ inputs = [a.path_from(bld.bldnode) for a in tsk.inputs]+ if env.FLEX_MSYS:+ inputs = [x.replace(os.sep, '/') for x in inputs]+ lst.extend(inputs)+ lst = [x for x in lst if x]+ txt = bld.cmd_and_log(lst, cwd=wd, env=env.env or None, quiet=0)+ tsk.outputs[0].write(txt.replace('\r\n', '\n').replace('\r', '\n')) # issue #1207++waflib.TaskGen.declare_chain(+ name = 'flex',+ rule = flexfun, # issue #854+ ext_in = '.l',+ decider = decide_ext,+)++def configure(conf):+ """+ Detect the *flex* program+ """+ conf.find_program('flex', var='FLEX')+ conf.env.FLEXFLAGS = ['-t']++ if re.search (r"\\msys\\[0-9.]+\\bin\\flex.exe$", conf.env.FLEX):+ # this is the flex shipped with MSYS+ conf.env.FLEX_MSYS = Truenew file mode 100644@@ -0,0 +1,67 @@+#! /usr/bin/env python+# encoding: utf-8+# KWS 2010+# Thomas Nagy 2010 (ita)++import re+from waflib import Utils+from waflib.Tools import fc, fc_config, fc_scan, ar+from waflib.Configure import conf++@conf+def find_g95(conf):+ fc = conf.find_program('g95', var='FC')+ fc = conf.cmd_to_list(fc)+ conf.get_g95_version(fc)+ conf.env.FC_NAME = 'G95'++@conf+def g95_flags(conf):+ v = conf.env+ v['FCFLAGS_fcshlib'] = ['-fPIC']+ v['FORTRANMODFLAG'] = ['-fmod=', ''] # template for module path+ v['FCFLAGS_DEBUG'] = ['-Werror'] # why not++@conf+def g95_modifier_win32(conf):+ fc_config.fortran_modifier_win32(conf)++@conf+def g95_modifier_cygwin(conf):+ fc_config.fortran_modifier_cygwin(conf)++@conf+def g95_modifier_darwin(conf):+ fc_config.fortran_modifier_darwin(conf)++@conf+def g95_modifier_platform(conf):+ dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()+ g95_modifier_func = getattr(conf, 'g95_modifier_' + dest_os, None)+ if g95_modifier_func:+ g95_modifier_func()++@conf+def get_g95_version(conf, fc):+ """get the compiler version"""++ version_re = re.compile(r"g95\s*(?P<major>\d*)\.(?P<minor>\d*)").search+ cmd = fc + ['--version']+ out, err = fc_config.getoutput(conf, cmd, stdin=False)+ if out:+ match = version_re(out)+ else:+ match = version_re(err)+ if not match:+ conf.fatal('cannot determine g95 version')+ k = match.groupdict()+ conf.env['FC_VERSION'] = (k['major'], k['minor'])++def configure(conf):+ conf.find_g95()+ conf.find_ar()+ conf.fc_flags()+ conf.fc_add_flags()+ conf.g95_flags()+ conf.g95_modifier_platform()+new file mode 100644@@ -0,0 +1,18 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2008-2010 (ita)++"Detect as/gas/gcc for compiling assembly files"++import waflib.Tools.asm # - leave this+from waflib.Tools import ar++def configure(conf):+ """+ Find the programs gas/as/gcc and set the variable *AS*+ """+ conf.find_program(['gas', 'gcc'], var='AS')+ conf.env.AS_TGT_F = ['-c', '-o']+ conf.env.ASLNK_TGT_F = ['-o']+ conf.find_ar()+ conf.load('asm')new file mode 100644@@ -0,0 +1,152 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)+# Ralf Habacker, 2006 (rh)+# Yinon Ehrlich, 2009++"""+gcc/llvm detection.+"""++import os, sys+from waflib import Configure, Options, Utils+from waflib.Tools import ccroot, ar+from waflib.Configure import conf++@conf+def find_gcc(conf):+ """+ Find the program gcc, and if present, try to detect its version number+ """+ cc = conf.find_program(['gcc', 'cc'], var='CC')+ cc = conf.cmd_to_list(cc)+ conf.get_cc_version(cc, gcc=True)+ conf.env.CC_NAME = 'gcc'+ conf.env.CC = cc++@conf+def gcc_common_flags(conf):+ """+ Common flags for gcc on nearly all platforms+ """+ v = conf.env++ v['CC_SRC_F'] = []+ v['CC_TGT_F'] = ['-c', '-o']++ # linker+ if not v['LINK_CC']: v['LINK_CC'] = v['CC']+ v['CCLNK_SRC_F'] = []+ v['CCLNK_TGT_F'] = ['-o']+ v['CPPPATH_ST'] = '-I%s'+ v['DEFINES_ST'] = '-D%s'++ v['LIB_ST'] = '-l%s' # template for adding libs+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths+ v['STLIB_ST'] = '-l%s'+ v['STLIBPATH_ST'] = '-L%s'+ v['RPATH_ST'] = '-Wl,-rpath,%s'++ v['SONAME_ST'] = '-Wl,-h,%s'+ v['SHLIB_MARKER'] = '-Wl,-Bdynamic'+ v['STLIB_MARKER'] = '-Wl,-Bstatic'++ # program+ v['cprogram_PATTERN'] = '%s'++ # shared librar+ v['CFLAGS_cshlib'] = ['-fPIC']+ v['LINKFLAGS_cshlib'] = ['-shared']+ v['cshlib_PATTERN'] = 'lib%s.so'++ # static lib+ v['LINKFLAGS_cstlib'] = ['-Wl,-Bstatic']+ v['cstlib_PATTERN'] = 'lib%s.a'++ # osx stuff+ v['LINKFLAGS_MACBUNDLE'] = ['-bundle', '-undefined', 'dynamic_lookup']+ v['CFLAGS_MACBUNDLE'] = ['-fPIC']+ v['macbundle_PATTERN'] = '%s.bundle'++@conf+def gcc_modifier_win32(conf):+ """Configuration flags for executing gcc on Windows"""+ v = conf.env+ v['cprogram_PATTERN'] = '%s.exe'++ v['cshlib_PATTERN'] = '%s.dll'+ v['implib_PATTERN'] = 'lib%s.dll.a'+ v['IMPLIB_ST'] = '-Wl,--out-implib,%s'++ v['CFLAGS_cshlib'] = []++ # Auto-import is enabled by default even without this option,+ # but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages+ # that the linker emits otherwise.+ v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import'])++@conf+def gcc_modifier_cygwin(conf):+ """Configuration flags for executing gcc on Cygwin"""+ gcc_modifier_win32(conf)+ v = conf.env+ v['cshlib_PATTERN'] = 'cyg%s.dll'+ v.append_value('LINKFLAGS_cshlib', ['-Wl,--enable-auto-image-base'])+ v['CFLAGS_cshlib'] = []++@conf+def gcc_modifier_darwin(conf):+ """Configuration flags for executing gcc on MacOS"""+ v = conf.env+ v['CFLAGS_cshlib'] = ['-fPIC', '-compatibility_version', '1', '-current_version', '1']+ v['LINKFLAGS_cshlib'] = ['-dynamiclib']+ v['cshlib_PATTERN'] = 'lib%s.dylib'+ v['FRAMEWORKPATH_ST'] = '-F%s'+ v['FRAMEWORK_ST'] = ['-framework']+ v['ARCH_ST'] = ['-arch']++ v['LINKFLAGS_cstlib'] = []++ v['SHLIB_MARKER'] = []+ v['STLIB_MARKER'] = []+ v['SONAME_ST'] = []++@conf+def gcc_modifier_aix(conf):+ """Configuration flags for executing gcc on AIX"""+ v = conf.env+ v['LINKFLAGS_cprogram'] = ['-Wl,-brtl']+ v['LINKFLAGS_cshlib'] = ['-shared','-Wl,-brtl,-bexpfull']+ v['SHLIB_MARKER'] = []++@conf+def gcc_modifier_hpux(conf):+ v = conf.env+ v['SHLIB_MARKER'] = []+ v['STLIB_MARKER'] = '-Bstatic'+ v['CFLAGS_cshlib'] = ['-fPIC','-DPIC']+ v['cshlib_PATTERN'] = 'lib%s.sl'++@conf+def gcc_modifier_platform(conf):+ """Execute platform-specific functions based on *gcc_modifier_+NAME*"""+ # * set configurations specific for a platform.+ # * the destination platform is detected automatically by looking at the macros the compiler predefines,+ # and if it's not recognised, it fallbacks to sys.platform.+ gcc_modifier_func = getattr(conf, 'gcc_modifier_' + conf.env.DEST_OS, None)+ if gcc_modifier_func:+ gcc_modifier_func()++def configure(conf):+ """+ Configuration for gcc+ """+ conf.find_gcc()+ conf.find_ar()+ conf.gcc_common_flags()+ conf.gcc_modifier_platform()+ conf.cc_load_tools()+ conf.cc_add_flags()+ conf.link_add_flags()++new file mode 100644@@ -0,0 +1,60 @@+#!/usr/bin/env python+# encoding: utf-8+# Carlos Rafael Giani, 2007 (dv)++import sys+from waflib.Tools import ar, d+from waflib.Configure import conf++@conf+def find_gdc(conf):+ """+ Find the program gdc and set the variable *D*+ """+ conf.find_program('gdc', var='D')++ out = conf.cmd_and_log([conf.env.D, '--version'])+ if out.find("gdc (GCC)") == -1:+ conf.fatal("detected compiler is not gdc")++@conf+def common_flags_gdc(conf):+ """+ Set the flags required by *gdc*+ """+ v = conf.env++ # _DFLAGS _DIMPORTFLAGS++ # for mory info about the meaning of this dict see dmd.py+ v['DFLAGS'] = []++ v['D_SRC_F'] = ['-c']+ v['D_TGT_F'] = '-o%s'++ # linker+ v['D_LINKER'] = v['D']+ v['DLNK_SRC_F'] = ''+ v['DLNK_TGT_F'] = '-o%s'+ v['DINC_ST'] = '-I%s'++ v['DSHLIB_MARKER'] = v['DSTLIB_MARKER'] = ''+ v['DSTLIB_ST'] = v['DSHLIB_ST'] = '-l%s'+ v['DSTLIBPATH_ST'] = v['DLIBPATH_ST'] = '-L%s'++ v['LINKFLAGS_dshlib'] = ['-shared']++ v['DHEADER_ext'] = '.di'+ v.DFLAGS_d_with_header = '-fintfc'+ v['D_HDR_F'] = '-fintfc-file=%s'++def configure(conf):+ """+ Configuration for gdc+ """+ conf.find_gdc()+ conf.load('ar')+ conf.load('d')+ conf.common_flags_gdc()+ conf.d_platform_flags()+new file mode 100644@@ -0,0 +1,91 @@+#! /usr/bin/env python+# encoding: utf-8+# DC 2008+# Thomas Nagy 2010 (ita)++import re+from waflib import Utils+from waflib.Tools import fc, fc_config, fc_scan, ar+from waflib.Configure import conf++@conf+def find_gfortran(conf):+ """Find the gfortran program (will look in the environment variable 'FC')"""+ fc = conf.find_program(['gfortran','g77'], var='FC')+ # (fallback to g77 for systems, where no gfortran is available)+ fc = conf.cmd_to_list(fc)+ conf.get_gfortran_version(fc)+ conf.env.FC_NAME = 'GFORTRAN'++@conf+def gfortran_flags(conf):+ v = conf.env+ v['FCFLAGS_fcshlib'] = ['-fPIC']+ v['FORTRANMODFLAG'] = ['-J', ''] # template for module path+ v['FCFLAGS_DEBUG'] = ['-Werror'] # why not++@conf+def gfortran_modifier_win32(conf):+ fc_config.fortran_modifier_win32(conf)++@conf+def gfortran_modifier_cygwin(conf):+ fc_config.fortran_modifier_cygwin(conf)++@conf+def gfortran_modifier_darwin(conf):+ fc_config.fortran_modifier_darwin(conf)++@conf+def gfortran_modifier_platform(conf):+ dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()+ gfortran_modifier_func = getattr(conf, 'gfortran_modifier_' + dest_os, None)+ if gfortran_modifier_func:+ gfortran_modifier_func()++@conf+def get_gfortran_version(conf, fc):+ """Get the compiler version"""++ # ensure this is actually gfortran, not an imposter.+ version_re = re.compile(r"GNU\s*Fortran", re.I).search+ cmd = fc + ['--version']+ out, err = fc_config.getoutput(conf, cmd, stdin=False)+ if out: match = version_re(out)+ else: match = version_re(err)+ if not match:+ conf.fatal('Could not determine the compiler type')++ # --- now get more detailed info -- see c_config.get_cc_version+ cmd = fc + ['-dM', '-E', '-']+ out, err = fc_config.getoutput(conf, cmd, stdin=True)++ if out.find('__GNUC__') < 0:+ conf.fatal('Could not determine the compiler type')++ k = {}+ out = out.split('\n')+ import shlex++ for line in out:+ lst = shlex.split(line)+ if len(lst)>2:+ key = lst[1]+ val = lst[2]+ k[key] = val++ def isD(var):+ return var in k++ def isT(var):+ return var in k and k[var] != '0'++ conf.env['FC_VERSION'] = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__'])++def configure(conf):+ conf.find_gfortran()+ conf.find_ar()+ conf.fc_flags()+ conf.fc_add_flags()+ conf.gfortran_flags()+ conf.gfortran_modifier_platform()new file mode 100644@@ -0,0 +1,378 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+Support for GLib2 tools:++* marshal+* enums+* gsettings+"""++import os+from waflib import Task, Utils, Options, Errors, Logs+from waflib.TaskGen import taskgen_method, before_method, after_method, feature++################## marshal files++@taskgen_method+def add_marshal_file(self, filename, prefix):+ """+ Add a file to the list of marshal files to process. Store them in the attribute *marshal_list*.++ :param filename: xml file to compile+ :type filename: string+ :param prefix: marshal prefix (--prefix=prefix)+ :type prefix: string+ """+ if not hasattr(self, 'marshal_list'):+ self.marshal_list = []+ self.meths.append('process_marshal')+ self.marshal_list.append((filename, prefix))++@before_method('process_source')+def process_marshal(self):+ """+ Process the marshal files stored in the attribute *marshal_list* to create :py:class:`waflib.Tools.glib2.glib_genmarshal` instances.+ Add the c file created to the list of source to process.+ """+ for f, prefix in getattr(self, 'marshal_list', []):+ node = self.path.find_resource(f)++ if not node:+ raise Errors.WafError('file not found %r' % f)++ h_node = node.change_ext('.h')+ c_node = node.change_ext('.c')++ task = self.create_task('glib_genmarshal', node, [h_node, c_node])+ task.env.GLIB_GENMARSHAL_PREFIX = prefix+ self.source = self.to_nodes(getattr(self, 'source', []))+ self.source.append(c_node)++class glib_genmarshal(Task.Task):++ def run(self):++ bld = self.inputs[0].__class__.ctx++ get = self.env.get_flat+ cmd1 = "%s %s --prefix=%s --header > %s" % (+ get('GLIB_GENMARSHAL'),+ self.inputs[0].srcpath(),+ get('GLIB_GENMARSHAL_PREFIX'),+ self.outputs[0].abspath()+ )++ ret = bld.exec_command(cmd1)+ if ret: return ret++ #print self.outputs[1].abspath()+ c = '''#include "%s"\n''' % self.outputs[0].name+ self.outputs[1].write(c)++ cmd2 = "%s %s --prefix=%s --body >> %s" % (+ get('GLIB_GENMARSHAL'),+ self.inputs[0].srcpath(),+ get('GLIB_GENMARSHAL_PREFIX'),+ self.outputs[1].abspath()+ )+ return bld.exec_command(cmd2)++ vars = ['GLIB_GENMARSHAL_PREFIX', 'GLIB_GENMARSHAL']+ color = 'BLUE'+ ext_out = ['.h']++########################## glib-mkenums++@taskgen_method+def add_enums_from_template(self, source='', target='', template='', comments=''):+ """+ Add a file to the list of enum files to process. Store them in the attribute *enums_list*.++ :param source: enum file to process+ :type source: string+ :param target: target file+ :type target: string+ :param template: template file+ :type template: string+ :param comments: comments+ :type comments: string+ """+ if not hasattr(self, 'enums_list'):+ self.enums_list = []+ self.meths.append('process_enums')+ self.enums_list.append({'source': source,+ 'target': target,+ 'template': template,+ 'file-head': '',+ 'file-prod': '',+ 'file-tail': '',+ 'enum-prod': '',+ 'value-head': '',+ 'value-prod': '',+ 'value-tail': '',+ 'comments': comments})++@taskgen_method+def add_enums(self, source='', target='',+ file_head='', file_prod='', file_tail='', enum_prod='',+ value_head='', value_prod='', value_tail='', comments=''):+ """+ Add a file to the list of enum files to process. Store them in the attribute *enums_list*.++ :param source: enum file to process+ :type source: string+ :param target: target file+ :type target: string+ :param file_head: unused+ :param file_prod: unused+ :param file_tail: unused+ :param enum_prod: unused+ :param value_head: unused+ :param value_prod: unused+ :param value_tail: unused+ :param comments: comments+ :type comments: string+ """+ if not hasattr(self, 'enums_list'):+ self.enums_list = []+ self.meths.append('process_enums')+ self.enums_list.append({'source': source,+ 'template': '',+ 'target': target,+ 'file-head': file_head,+ 'file-prod': file_prod,+ 'file-tail': file_tail,+ 'enum-prod': enum_prod,+ 'value-head': value_head,+ 'value-prod': value_prod,+ 'value-tail': value_tail,+ 'comments': comments})++@before_method('process_source')+def process_enums(self):+ """+ Process the enum files stored in the attribute *enum_list* to create :py:class:`waflib.Tools.glib2.glib_mkenums` instances.+ """+ for enum in getattr(self, 'enums_list', []):+ task = self.create_task('glib_mkenums')+ env = task.env++ inputs = []++ # process the source+ source_list = self.to_list(enum['source'])+ if not source_list:+ raise Errors.WafError('missing source ' + str(enum))+ source_list = [self.path.find_resource(k) for k in source_list]+ inputs += source_list+ env['GLIB_MKENUMS_SOURCE'] = [k.abspath() for k in source_list]++ # find the target+ if not enum['target']:+ raise Errors.WafError('missing target ' + str(enum))+ tgt_node = self.path.find_or_declare(enum['target'])+ if tgt_node.name.endswith('.c'):+ self.source.append(tgt_node)+ env['GLIB_MKENUMS_TARGET'] = tgt_node.abspath()+++ options = []++ if enum['template']: # template, if provided+ template_node = self.path.find_resource(enum['template'])+ options.append('--template %s' % (template_node.abspath()))+ inputs.append(template_node)+ params = {'file-head' : '--fhead',+ 'file-prod' : '--fprod',+ 'file-tail' : '--ftail',+ 'enum-prod' : '--eprod',+ 'value-head' : '--vhead',+ 'value-prod' : '--vprod',+ 'value-tail' : '--vtail',+ 'comments': '--comments'}+ for param, option in params.items():+ if enum[param]:+ options.append('%s %r' % (option, enum[param]))++ env['GLIB_MKENUMS_OPTIONS'] = ' '.join(options)++ # update the task instance+ task.set_inputs(inputs)+ task.set_outputs(tgt_node)++class glib_mkenums(Task.Task):+ """+ Process enum files+ """+ run_str = '${GLIB_MKENUMS} ${GLIB_MKENUMS_OPTIONS} ${GLIB_MKENUMS_SOURCE} > ${GLIB_MKENUMS_TARGET}'+ color = 'PINK'+ ext_out = ['.h']++######################################### gsettings++@taskgen_method+def add_settings_schemas(self, filename_list):+ """+ Add settings files to process, add them to *settings_schema_files*++ :param filename_list: files+ :type filename_list: list of string+ """+ if not hasattr(self, 'settings_schema_files'):+ self.settings_schema_files = []++ if not isinstance(filename_list, list):+ filename_list = [filename_list]++ self.settings_schema_files.extend(filename_list)++@taskgen_method+def add_settings_enums(self, namespace, filename_list):+ """+ This function may be called only once by task generator to set the enums namespace.++ :param namespace: namespace+ :type namespace: string+ :param filename_list: enum files to process+ :type filename_list: file list+ """+ if hasattr(self, 'settings_enum_namespace'):+ raise Errors.WafError("Tried to add gsettings enums to '%s' more than once" % self.name)+ self.settings_enum_namespace = namespace++ if type(filename_list) != 'list':+ filename_list = [filename_list]+ self.settings_enum_files = filename_list+++def r_change_ext(self, ext):+ """+ Change the extension from the *last* dot in the filename. The gsettings schemas+ often have names of the form org.gsettings.test.gschema.xml+ """+ name = self.name+ k = name.rfind('.')+ if k >= 0:+ name = name[:k] + ext+ else:+ name = name + ext+ return self.parent.find_or_declare([name])++@feature('glib2')+def process_settings(self):+ """+ Process the schema files in *settings_schema_files* to create :py:class:`waflib.Tools.glib2.glib_mkenums` instances. The+ same files are validated through :py:class:`waflib.Tools.glib2.glib_validate_schema` tasks.++ """+ enums_tgt_node = []+ install_files = []++ settings_schema_files = getattr(self, 'settings_schema_files', [])+ if settings_schema_files and not self.env['GLIB_COMPILE_SCHEMAS']:+ raise Errors.WafError ("Unable to process GSettings schemas - glib-compile-schemas was not found during configure")++ # 1. process gsettings_enum_files (generate .enums.xml)+ #+ if hasattr(self, 'settings_enum_files'):+ enums_task = self.create_task('glib_mkenums')++ source_list = self.settings_enum_files+ source_list = [self.path.find_resource(k) for k in source_list]+ enums_task.set_inputs(source_list)+ enums_task.env['GLIB_MKENUMS_SOURCE'] = [k.abspath() for k in source_list]++ target = self.settings_enum_namespace + '.enums.xml'+ tgt_node = self.path.find_or_declare(target)+ enums_task.set_outputs(tgt_node)+ enums_task.env['GLIB_MKENUMS_TARGET'] = tgt_node.abspath()+ enums_tgt_node = [tgt_node]++ install_files.append (tgt_node)++ options = '--comments "<!-- @comment@ -->" --fhead "<schemalist>" --vhead " <@type@ id=\\"%s.@EnumName@\\">" --vprod " <value nick=\\"@valuenick@\\" value=\\"@valuenum@\\"/>" --vtail " </@type@>" --ftail "</schemalist>" ' % (self.settings_enum_namespace)+ enums_task.env['GLIB_MKENUMS_OPTIONS'] = options++ # 2. process gsettings_schema_files (validate .gschema.xml files)+ #+ for schema in settings_schema_files:+ schema_task = self.create_task ('glib_validate_schema')++ schema_node = self.path.find_resource(schema)+ if not schema_node:+ raise Errors.WafError("Cannot find the schema file '%s'" % schema)+ install_files.append(schema_node)+ source_list = enums_tgt_node + [schema_node]++ schema_task.set_inputs (source_list)+ schema_task.env['GLIB_COMPILE_SCHEMAS_OPTIONS'] = [("--schema-file=" + k.abspath()) for k in source_list]++ target_node = r_change_ext (schema_node, '.xml.valid')+ schema_task.set_outputs (target_node)+ schema_task.env['GLIB_VALIDATE_SCHEMA_OUTPUT'] = target_node.abspath()++ # 3. schemas install task+ def compile_schemas_callback(bld):+ if not bld.is_install: return+ Logs.pprint ('YELLOW','Updating GSettings schema cache')+ command = Utils.subst_vars("${GLIB_COMPILE_SCHEMAS} ${GSETTINGSSCHEMADIR}", bld.env)+ ret = self.bld.exec_command(command)++ if self.bld.is_install:+ if not self.env['GSETTINGSSCHEMADIR']:+ raise Errors.WafError ('GSETTINGSSCHEMADIR not defined (should have been set up automatically during configure)')++ if install_files:+ self.bld.install_files (self.env['GSETTINGSSCHEMADIR'], install_files)++ if not hasattr(self.bld, '_compile_schemas_registered'):+ self.bld.add_post_fun (compile_schemas_callback)+ self.bld._compile_schemas_registered = True++class glib_validate_schema(Task.Task):+ """+ Validate schema files+ """+ run_str = 'rm -f ${GLIB_VALIDATE_SCHEMA_OUTPUT} && ${GLIB_COMPILE_SCHEMAS} --dry-run ${GLIB_COMPILE_SCHEMAS_OPTIONS} && touch ${GLIB_VALIDATE_SCHEMA_OUTPUT}'+ color = 'PINK'++def configure(conf):+ """+ Find the following programs:++ * *glib-genmarshal* and set *GLIB_GENMARSHAL*+ * *glib-mkenums* and set *GLIB_MKENUMS*+ * *glib-compile-schemas* and set *GLIB_COMPILE_SCHEMAS* (not mandatory)++ And set the variable *GSETTINGSSCHEMADIR*+ """+ conf.find_program('glib-genmarshal', var='GLIB_GENMARSHAL')+ conf.find_perl_program('glib-mkenums', var='GLIB_MKENUMS')++ # when cross-compiling, gsettings.m4 locates the program with the following:+ # pkg-config --variable glib_compile_schemas gio-2.0+ conf.find_program('glib-compile-schemas', var='GLIB_COMPILE_SCHEMAS', mandatory=False)++ def getstr(varname):+ return getattr(Options.options, varname, getattr(conf.env,varname, ''))++ # TODO make this dependent on the gnu_dirs tool?+ gsettingsschemadir = getstr('GSETTINGSSCHEMADIR')+ if not gsettingsschemadir:+ datadir = getstr('DATADIR')+ if not datadir:+ prefix = conf.env['PREFIX']+ datadir = os.path.join(prefix, 'share')+ gsettingsschemadir = os.path.join(datadir, 'glib-2.0', 'schemas')++ conf.env['GSETTINGSSCHEMADIR'] = gsettingsschemadir++def options(opt):+ """+ Add the ``--gsettingsschemadir`` command-line option+ """+ opt.add_option('--gsettingsschemadir', help='GSettings schema location [Default: ${datadir}/glib-2.0/schemas]',default='',dest='GSETTINGSSCHEMADIR')+new file mode 100644@@ -0,0 +1,129 @@+#!/usr/bin/env python+# encoding: utf-8+# Ali Sabil, 2007++"""+Sets various standard variables such as INCLUDEDIR. SBINDIR and others. To use this module just call::++ opt.load('gnu_dirs')++and::++ conf.load('gnu_dirs')++Add options for the standard GNU directories, this tool will add the options+found in autotools, and will update the environment with the following+installation variables:++============== ========================================= =======================+Variable Description Value+============== ========================================= =======================+PREFIX architecture-independent files /usr/local+EXEC_PREFIX architecture-dependent files PREFIX+BINDIR user executables EXEC_PREFIX/bin+SBINDIR user executables EXEC_PREFIX/sbin+LIBEXECDIR program executables EXEC_PREFIX/libexec+SYSCONFDIR read-only single-machine data PREFIX/etc+SHAREDSTATEDIR modifiable architecture-independent data PREFIX/com+LOCALSTATEDIR modifiable single-machine data PREFIX/var+LIBDIR object code libraries EXEC_PREFIX/lib+INCLUDEDIR C header files PREFIX/include+OLDINCLUDEDIR C header files for non-gcc /usr/include+DATAROOTDIR read-only arch.-independent data root PREFIX/share+DATADIR read-only architecture-independent data DATAROOTDIR+INFODIR info documentation DATAROOTDIR/info+LOCALEDIR locale-dependent data DATAROOTDIR/locale+MANDIR man documentation DATAROOTDIR/man+DOCDIR documentation root DATAROOTDIR/doc/APPNAME+HTMLDIR html documentation DOCDIR+DVIDIR dvi documentation DOCDIR+PDFDIR pdf documentation DOCDIR+PSDIR ps documentation DOCDIR+============== ========================================= =======================+"""++import os+from waflib import Utils, Options, Context++_options = [x.split(', ') for x in '''+bindir, user executables, ${EXEC_PREFIX}/bin+sbindir, system admin executables, ${EXEC_PREFIX}/sbin+libexecdir, program executables, ${EXEC_PREFIX}/libexec+sysconfdir, read-only single-machine data, ${PREFIX}/etc+sharedstatedir, modifiable architecture-independent data, ${PREFIX}/com+localstatedir, modifiable single-machine data, ${PREFIX}/var+libdir, object code libraries, ${EXEC_PREFIX}/lib+includedir, C header files, ${PREFIX}/include+oldincludedir, C header files for non-gcc, /usr/include+datarootdir, read-only arch.-independent data root, ${PREFIX}/share+datadir, read-only architecture-independent data, ${DATAROOTDIR}+infodir, info documentation, ${DATAROOTDIR}/info+localedir, locale-dependent data, ${DATAROOTDIR}/locale+mandir, man documentation, ${DATAROOTDIR}/man+docdir, documentation root, ${DATAROOTDIR}/doc/${PACKAGE}+htmldir, html documentation, ${DOCDIR}+dvidir, dvi documentation, ${DOCDIR}+pdfdir, pdf documentation, ${DOCDIR}+psdir, ps documentation, ${DOCDIR}+'''.split('\n') if x]++def configure(conf):+ """+ Read the command-line options to set lots of variables in *conf.env*. The variables+ BINDIR and LIBDIR will be overwritten.+ """+ def get_param(varname, default):+ return getattr(Options.options, varname, '') or default++ env = conf.env+ env.LIBDIR = env.BINDIR = []+ env.EXEC_PREFIX = get_param('EXEC_PREFIX', env.PREFIX)+ env.PACKAGE = getattr(Context.g_module, 'APPNAME', None) or env.PACKAGE++ complete = False+ iter = 0+ while not complete and iter < len(_options) + 1:+ iter += 1+ complete = True+ for name, help, default in _options:+ name = name.upper()+ if not env[name]:+ try:+ env[name] = Utils.subst_vars(get_param(name, default).replace('/', os.sep), env)+ except TypeError:+ complete = False++ if not complete:+ lst = [name for name, _, _ in _options if not env[name.upper()]]+ raise conf.errors.WafError('Variable substitution failure %r' % lst)++def options(opt):+ """+ Add lots of command-line options, for example::++ --exec-prefix: EXEC_PREFIX+ """+ inst_dir = opt.add_option_group('Installation directories',+'By default, "waf install" will put the files in\+ "/usr/local/bin", "/usr/local/lib" etc. An installation prefix other\+ than "/usr/local" can be given using "--prefix", for example "--prefix=$HOME"')++ for k in ('--prefix', '--destdir'):+ option = opt.parser.get_option(k)+ if option:+ opt.parser.remove_option(k)+ inst_dir.add_option(option)++ inst_dir.add_option('--exec-prefix',+ help = 'installation prefix [Default: ${PREFIX}]',+ default = '',+ dest = 'EXEC_PREFIX')++ dirs_options = opt.add_option_group('Pre-defined installation directories', '')++ for name, help, default in _options:+ option_name = '--' + name+ str_default = default+ str_help = '%s [Default: %s]' % (help, str_default)+ dirs_options.add_option(option_name, help=str_help, default='', dest=name.upper())+new file mode 100644@@ -0,0 +1,152 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)+# Ralf Habacker, 2006 (rh)+# Yinon Ehrlich, 2009++"""+g++/llvm detection.+"""++import os, sys+from waflib import Configure, Options, Utils+from waflib.Tools import ccroot, ar+from waflib.Configure import conf++@conf+def find_gxx(conf):+ """+ Find the program g++, and if present, try to detect its version number+ """+ cxx = conf.find_program(['g++', 'c++'], var='CXX')+ cxx = conf.cmd_to_list(cxx)+ conf.get_cc_version(cxx, gcc=True)+ conf.env.CXX_NAME = 'gcc'+ conf.env.CXX = cxx++@conf+def gxx_common_flags(conf):+ """+ Common flags for g++ on nearly all platforms+ """+ v = conf.env++ v['CXX_SRC_F'] = []+ v['CXX_TGT_F'] = ['-c', '-o']++ # linker+ if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX']+ v['CXXLNK_SRC_F'] = []+ v['CXXLNK_TGT_F'] = ['-o']+ v['CPPPATH_ST'] = '-I%s'+ v['DEFINES_ST'] = '-D%s'++ v['LIB_ST'] = '-l%s' # template for adding libs+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths+ v['STLIB_ST'] = '-l%s'+ v['STLIBPATH_ST'] = '-L%s'+ v['RPATH_ST'] = '-Wl,-rpath,%s'++ v['SONAME_ST'] = '-Wl,-h,%s'+ v['SHLIB_MARKER'] = '-Wl,-Bdynamic'+ v['STLIB_MARKER'] = '-Wl,-Bstatic'++ # program+ v['cxxprogram_PATTERN'] = '%s'++ # shared library+ v['CXXFLAGS_cxxshlib'] = ['-fPIC']+ v['LINKFLAGS_cxxshlib'] = ['-shared']+ v['cxxshlib_PATTERN'] = 'lib%s.so'++ # static lib+ v['LINKFLAGS_cxxstlib'] = ['-Wl,-Bstatic']+ v['cxxstlib_PATTERN'] = 'lib%s.a'++ # osx stuff+ v['LINKFLAGS_MACBUNDLE'] = ['-bundle', '-undefined', 'dynamic_lookup']+ v['CXXFLAGS_MACBUNDLE'] = ['-fPIC']+ v['macbundle_PATTERN'] = '%s.bundle'++@conf+def gxx_modifier_win32(conf):+ """Configuration flags for executing gcc on Windows"""+ v = conf.env+ v['cxxprogram_PATTERN'] = '%s.exe'++ v['cxxshlib_PATTERN'] = '%s.dll'+ v['implib_PATTERN'] = 'lib%s.dll.a'+ v['IMPLIB_ST'] = '-Wl,--out-implib,%s'++ v['CXXFLAGS_cxxshlib'] = []++ # Auto-import is enabled by default even without this option,+ # but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages+ # that the linker emits otherwise.+ v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import'])++@conf+def gxx_modifier_cygwin(conf):+ """Configuration flags for executing g++ on Cygwin"""+ gxx_modifier_win32(conf)+ v = conf.env+ v['cxxshlib_PATTERN'] = 'cyg%s.dll'+ v.append_value('LINKFLAGS_cxxshlib', ['-Wl,--enable-auto-image-base'])+ v['CXXFLAGS_cxxshlib'] = []++@conf+def gxx_modifier_darwin(conf):+ """Configuration flags for executing g++ on MacOS"""+ v = conf.env+ v['CXXFLAGS_cxxshlib'] = ['-fPIC', '-compatibility_version', '1', '-current_version', '1']+ v['LINKFLAGS_cxxshlib'] = ['-dynamiclib']+ v['cxxshlib_PATTERN'] = 'lib%s.dylib'+ v['FRAMEWORKPATH_ST'] = '-F%s'+ v['FRAMEWORK_ST'] = ['-framework']+ v['ARCH_ST'] = ['-arch']++ v['LINKFLAGS_cxxstlib'] = []++ v['SHLIB_MARKER'] = []+ v['STLIB_MARKER'] = []+ v['SONAME_ST'] = []++@conf+def gxx_modifier_aix(conf):+ """Configuration flags for executing g++ on AIX"""+ v = conf.env+ v['LINKFLAGS_cxxprogram']= ['-Wl,-brtl']++ v['LINKFLAGS_cxxshlib'] = ['-shared', '-Wl,-brtl,-bexpfull']+ v['SHLIB_MARKER'] = []++@conf+def gxx_modifier_hpux(conf):+ v = conf.env+ v['SHLIB_MARKER'] = []+ v['STLIB_MARKER'] = '-Bstatic'+ v['CFLAGS_cxxshlib'] = ['-fPIC','-DPIC']+ v['cxxshlib_PATTERN'] = 'lib%s.sl'++@conf+def gxx_modifier_platform(conf):+ """Execute platform-specific functions based on *gxx_modifier_+NAME*"""+ # * set configurations specific for a platform.+ # * the destination platform is detected automatically by looking at the macros the compiler predefines,+ # and if it's not recognised, it fallbacks to sys.platform.+ gxx_modifier_func = getattr(conf, 'gxx_modifier_' + conf.env.DEST_OS, None)+ if gxx_modifier_func:+ gxx_modifier_func()++def configure(conf):+ """+ Configuration for g+++ """+ conf.find_gxx()+ conf.find_ar()+ conf.gxx_common_flags()+ conf.gxx_modifier_platform()+ conf.cxx_load_tools()+ conf.cxx_add_flags()+ conf.link_add_flags()+new file mode 100644@@ -0,0 +1,42 @@+#!/usr/bin/env python+# encoding: utf-8+# Stian Selnes, 2008+# Thomas Nagy 2009-2010 (ita)++"""+Detect the Intel C compiler+"""++import os, sys+from waflib.Tools import ccroot, ar, gcc+from waflib.Configure import conf++@conf+def find_icc(conf):+ """+ Find the program icc and execute it to ensure it really is icc+ """+ if sys.platform == 'cygwin':+ conf.fatal('The Intel compiler does not work on Cygwin')++ v = conf.env+ cc = None+ if v['CC']: cc = v['CC']+ elif 'CC' in conf.environ: cc = conf.environ['CC']+ if not cc: cc = conf.find_program('icc', var='CC')+ if not cc: cc = conf.find_program('ICL', var='CC')+ if not cc: conf.fatal('Intel C Compiler (icc) was not found')+ cc = conf.cmd_to_list(cc)++ conf.get_cc_version(cc, icc=True)+ v['CC'] = cc+ v['CC_NAME'] = 'icc'++def configure(conf):+ conf.find_icc()+ conf.find_ar()+ conf.gcc_common_flags()+ conf.gcc_modifier_platform()+ conf.cc_load_tools()+ conf.cc_add_flags()+ conf.link_add_flags()new file mode 100644@@ -0,0 +1,41 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy 2009-2010 (ita)++"""+Detect the Intel C++ compiler+"""++import os, sys+from waflib.Tools import ccroot, ar, gxx+from waflib.Configure import conf++@conf+def find_icpc(conf):+ """+ Find the program icpc, and execute it to ensure it really is icpc+ """+ if sys.platform == 'cygwin':+ conf.fatal('The Intel compiler does not work on Cygwin')++ v = conf.env+ cxx = None+ if v['CXX']: cxx = v['CXX']+ elif 'CXX' in conf.environ: cxx = conf.environ['CXX']+ if not cxx: cxx = conf.find_program('icpc', var='CXX')+ if not cxx: conf.fatal('Intel C++ Compiler (icpc) was not found')+ cxx = conf.cmd_to_list(cxx)++ conf.get_cc_version(cxx, icc=True)+ v['CXX'] = cxx+ v['CXX_NAME'] = 'icc'++def configure(conf):+ conf.find_icpc()+ conf.find_ar()+ conf.gxx_common_flags()+ conf.gxx_modifier_platform()+ conf.cxx_load_tools()+ conf.cxx_add_flags()+ conf.link_add_flags()+new file mode 100644@@ -0,0 +1,60 @@+#! /usr/bin/env python+# encoding: utf-8+# DC 2008+# Thomas Nagy 2010 (ita)++import re+from waflib import Utils+from waflib.Tools import fc, fc_config, fc_scan, ar+from waflib.Configure import conf++@conf+def find_ifort(conf):+ fc = conf.find_program('ifort', var='FC')+ fc = conf.cmd_to_list(fc)+ conf.get_ifort_version(fc)+ conf.env.FC_NAME = 'IFORT'++@conf+def ifort_modifier_cygwin(conf):+ raise NotImplementedError("Ifort on cygwin not yet implemented")++@conf+def ifort_modifier_win32(conf):+ fc_config.fortran_modifier_win32(conf)++@conf+def ifort_modifier_darwin(conf):+ fc_config.fortran_modifier_darwin(conf)++@conf+def ifort_modifier_platform(conf):+ dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()+ ifort_modifier_func = getattr(conf, 'ifort_modifier_' + dest_os, None)+ if ifort_modifier_func:+ ifort_modifier_func()++@conf+def get_ifort_version(conf, fc):+ """get the compiler version"""++ version_re = re.compile(r"ifort\s*\(IFORT\)\s*(?P<major>\d*)\.(?P<minor>\d*)", re.I).search+ cmd = fc + ['--version']+ out, err = fc_config.getoutput(conf, cmd, stdin=False)+ if out:+ match = version_re(out)+ else:+ match = version_re(err)+ if not match:+ conf.fatal('cannot determine ifort version.')+ k = match.groupdict()+ conf.env['FC_VERSION'] = (k['major'], k['minor'])++def configure(conf):+ conf.find_ifort()+ conf.find_program('xiar', var='AR')+ conf.env.ARFLAGS = 'rcs'+ conf.fc_flags()+ conf.fc_add_flags()+ conf.ifort_modifier_platform()+new file mode 100644@@ -0,0 +1,176 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+Support for translation tools such as msgfmt and intltool++Usage::++ def configure(conf):+ conf.load('gnu_dirs intltool')++ def build(bld):+ # process the .po files into .gmo files, and install them in LOCALEDIR+ bld(features='intltool_po', appname='myapp', podir='po', install_path="${LOCALEDIR}")++ # process an input file, substituting the translations from the po dir+ bld(+ features = "intltool_in",+ podir = "../po",+ flags = ["-d", "-q", "-u", "-c"],+ source = 'kupfer.desktop.in',+ install_path = "${DATADIR}/applications",+ )++Usage of the :py:mod:`waflib.Tools.gnu_dirs` is recommended, but not obligatory.+"""++import os, re+from waflib import Configure, TaskGen, Task, Utils, Runner, Options, Build, Logs+import waflib.Tools.ccroot+from waflib.TaskGen import feature, before_method+from waflib.Logs import error++@before_method('process_source')+@feature('intltool_in')+def apply_intltool_in_f(self):+ """+ Create tasks to translate files by intltool-merge::++ def build(bld):+ bld(+ features = "intltool_in",+ podir = "../po",+ flags = ["-d", "-q", "-u", "-c"],+ source = 'kupfer.desktop.in',+ install_path = "${DATADIR}/applications",+ )++ :param podir: location of the .po files+ :type podir: string+ :param source: source files to process+ :type source: list of string+ :param flags: compilation flags ("-quc" by default)+ :type flags: list of string+ :param install_path: installation path+ :type install_path: string+ """+ try: self.meths.remove('process_source')+ except ValueError: pass++ if not self.env.LOCALEDIR:+ self.env.LOCALEDIR = self.env.PREFIX + '/share/locale'++ for i in self.to_list(self.source):+ node = self.path.find_resource(i)++ podir = getattr(self, 'podir', 'po')+ podirnode = self.path.find_dir(podir)+ if not podirnode:+ error("could not find the podir %r" % podir)+ continue++ cache = getattr(self, 'intlcache', '.intlcache')+ self.env['INTLCACHE'] = os.path.join(self.path.bldpath(), podir, cache)+ self.env['INTLPODIR'] = podirnode.bldpath()+ self.env['INTLFLAGS'] = getattr(self, 'flags', ['-q', '-u', '-c'])++ task = self.create_task('intltool', node, node.change_ext(''))+ inst = getattr(self, 'install_path', '${LOCALEDIR}')+ if inst:+ self.bld.install_files(inst, task.outputs)++@feature('intltool_po')+def apply_intltool_po(self):+ """+ Create tasks to process po files::++ def build(bld):+ bld(features='intltool_po', appname='myapp', podir='po', install_path="${LOCALEDIR}")++ The relevant task generator arguments are:++ :param podir: directory of the .po files+ :type podir: string+ :param appname: name of the application+ :type appname: string+ :param install_path: installation directory+ :type install_path: string++ The file LINGUAS must be present in the directory pointed by *podir* and list the translation files to process.+ """+ try: self.meths.remove('process_source')+ except ValueError: pass++ if not self.env.LOCALEDIR:+ self.env.LOCALEDIR = self.env.PREFIX + '/share/locale'++ appname = getattr(self, 'appname', 'set_your_app_name')+ podir = getattr(self, 'podir', '')+ inst = getattr(self, 'install_path', '${LOCALEDIR}')++ linguas = self.path.find_node(os.path.join(podir, 'LINGUAS'))+ if linguas:+ # scan LINGUAS file for locales to process+ file = open(linguas.abspath())+ langs = []+ for line in file.readlines():+ # ignore lines containing comments+ if not line.startswith('#'):+ langs += line.split()+ file.close()+ re_linguas = re.compile('[-a-zA-Z_@.]+')+ for lang in langs:+ # Make sure that we only process lines which contain locales+ if re_linguas.match(lang):+ node = self.path.find_resource(os.path.join(podir, re_linguas.match(lang).group() + '.po'))+ task = self.create_task('po', node, node.change_ext('.mo'))++ if inst:+ filename = task.outputs[0].name+ (langname, ext) = os.path.splitext(filename)+ inst_file = inst + os.sep + langname + os.sep + 'LC_MESSAGES' + os.sep + appname + '.mo'+ self.bld.install_as(inst_file, task.outputs[0], chmod=getattr(self, 'chmod', Utils.O644), env=task.env)++ else:+ Logs.pprint('RED', "Error no LINGUAS file found in po directory")++class po(Task.Task):+ """+ Compile .po files into .gmo files+ """+ run_str = '${MSGFMT} -o ${TGT} ${SRC}'+ color = 'BLUE'++class intltool(Task.Task):+ """+ Let intltool-merge translate an input file+ """+ run_str = '${INTLTOOL} ${INTLFLAGS} ${INTLCACHE} ${INTLPODIR} ${SRC} ${TGT}'+ color = 'BLUE'++def configure(conf):+ """+ Detect the program *msgfmt* and set *conf.env.MSGFMT*.+ Detect the program *intltool-merge* and set *conf.env.INTLTOOL*.+ It is possible to set INTLTOOL in the environment, but it must not have spaces in it::++ $ INTLTOOL="/path/to/the program/intltool" waf configure++ If a C/C++ compiler is present, execute a compilation test to find the header *locale.h*.+ """+ conf.find_program('msgfmt', var='MSGFMT')+ conf.find_perl_program('intltool-merge', var='INTLTOOL')++ prefix = conf.env.PREFIX+ datadir = conf.env.DATADIR+ if not datadir:+ datadir = os.path.join(prefix,'share')++ conf.define('LOCALEDIR', os.path.join(datadir, 'locale').replace('\\', '\\\\'))+ conf.define('DATADIR', datadir.replace('\\', '\\\\'))++ if conf.env.CC or conf.env.CXX:+ conf.check(header_name='locale.h')+new file mode 100644@@ -0,0 +1,63 @@+#! /usr/bin/env python+# imported from samba++"""+compiler definition for irix/MIPSpro cc compiler+based on suncc.py from waf+"""++import os+from waflib import Utils+from waflib.Tools import ccroot, ar+from waflib.Configure import conf++@conf+def find_irixcc(conf):+ v = conf.env+ cc = None+ if v['CC']: cc = v['CC']+ elif 'CC' in conf.environ: cc = conf.environ['CC']+ if not cc: cc = conf.find_program('cc', var='CC')+ if not cc: conf.fatal('irixcc was not found')+ cc = conf.cmd_to_list(cc)++ try:+ conf.cmd_and_log(cc + ['-version'])+ except Exception:+ conf.fatal('%r -version could not be executed' % cc)++ v['CC'] = cc+ v['CC_NAME'] = 'irix'++@conf+def irixcc_common_flags(conf):+ v = conf.env++ v['CC_SRC_F'] = ''+ v['CC_TGT_F'] = ['-c', '-o']+ v['CPPPATH_ST'] = '-I%s'+ v['DEFINES_ST'] = '-D%s'++ # linker+ if not v['LINK_CC']: v['LINK_CC'] = v['CC']+ v['CCLNK_SRC_F'] = ''+ v['CCLNK_TGT_F'] = ['-o']++ v['LIB_ST'] = '-l%s' # template for adding libs+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths+ v['STLIB_ST'] = '-l%s'+ v['STLIBPATH_ST'] = '-L%s'++ v['cprogram_PATTERN'] = '%s'+ v['cshlib_PATTERN'] = 'lib%s.so'+ v['cstlib_PATTERN'] = 'lib%s.a'++def configure(conf):+ conf.find_irixcc()+ conf.find_cpp()+ conf.find_ar()+ conf.irixcc_common_flags()+ conf.cc_load_tools()+ conf.cc_add_flags()+ conf.link_add_flags()+new file mode 100644@@ -0,0 +1,482 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+Java support++Javac is one of the few compilers that behaves very badly:++#. it outputs files where it wants to (-d is only for the package root)++#. it recompiles files silently behind your back++#. it outputs an undefined amount of files (inner classes)++Remember that the compilation can be performed using Jython[1] rather than regular Python. Instead of+running one of the following commands::++ ./waf configure+ python waf configure++You would have to run::++ java -jar /path/to/jython.jar waf configure++[1] http://www.jython.org/+"""++import os, re, tempfile, shutil+from waflib import TaskGen, Task, Utils, Options, Build, Errors, Node, Logs+from waflib.Configure import conf+from waflib.TaskGen import feature, before_method, after_method++from waflib.Tools import ccroot+ccroot.USELIB_VARS['javac'] = set(['CLASSPATH', 'JAVACFLAGS'])+++SOURCE_RE = '**/*.java'+JAR_RE = '**/*'++class_check_source = '''+public class Test {+ public static void main(String[] argv) {+ Class lib;+ if (argv.length < 1) {+ System.err.println("Missing argument");+ System.exit(77);+ }+ try {+ lib = Class.forName(argv[0]);+ } catch (ClassNotFoundException e) {+ System.err.println("ClassNotFoundException");+ System.exit(1);+ }+ lib = null;+ System.exit(0);+ }+}+'''++@feature('javac')+@before_method('process_source')+def apply_java(self):+ """+ Create a javac task for compiling *.java files*. There can be+ only one javac task by task generator.+ """+ Utils.def_attrs(self, jarname='', classpath='',+ sourcepath='.', srcdir='.',+ jar_mf_attributes={}, jar_mf_classpath=[])++ nodes_lst = []++ outdir = getattr(self, 'outdir', None)+ if outdir:+ if not isinstance(outdir, Node.Node):+ outdir = self.path.get_bld().make_node(self.outdir)+ else:+ outdir = self.path.get_bld()+ outdir.mkdir()+ self.outdir = outdir+ self.env['OUTDIR'] = outdir.abspath()++ self.javac_task = tsk = self.create_task('javac')+ tmp = []++ srcdir = getattr(self, 'srcdir', '')+ if isinstance(srcdir, Node.Node):+ srcdir = [srcdir]+ for x in Utils.to_list(srcdir):+ if isinstance(x, Node.Node):+ y = x+ else:+ y = self.path.find_dir(x)+ if not y:+ self.bld.fatal('Could not find the folder %s from %s' % (x, self.path))+ tmp.append(y)+ tsk.srcdir = tmp++ if getattr(self, 'compat', None):+ tsk.env.append_value('JAVACFLAGS', ['-source', self.compat])++ if hasattr(self, 'sourcepath'):+ fold = [isinstance(x, Node.Node) and x or self.path.find_dir(x) for x in self.to_list(self.sourcepath)]+ names = os.pathsep.join([x.srcpath() for x in fold])+ else:+ names = [x.srcpath() for x in tsk.srcdir]++ if names:+ tsk.env.append_value('JAVACFLAGS', ['-sourcepath', names])++@feature('javac')+@after_method('apply_java')+def use_javac_files(self):+ """+ Process the *use* attribute referring to other java compilations+ """+ lst = []+ self.uselib = self.to_list(getattr(self, 'uselib', []))+ names = self.to_list(getattr(self, 'use', []))+ get = self.bld.get_tgen_by_name+ for x in names:+ try:+ y = get(x)+ except Exception:+ self.uselib.append(x)+ else:+ y.post()+ lst.append(y.jar_task.outputs[0].abspath())+ self.javac_task.set_run_after(y.jar_task)++ if lst:+ self.env.append_value('CLASSPATH', lst)++@feature('javac')+@after_method('apply_java', 'propagate_uselib_vars', 'use_javac_files')+def set_classpath(self):+ """+ Set the CLASSPATH value on the *javac* task previously created.+ """+ self.env.append_value('CLASSPATH', getattr(self, 'classpath', []))+ for x in self.tasks:+ x.env.CLASSPATH = os.pathsep.join(self.env.CLASSPATH) + os.pathsep++@feature('jar')+@after_method('apply_java', 'use_javac_files')+@before_method('process_source')+def jar_files(self):+ """+ Create a jar task. There can be only one jar task by task generator.+ """+ destfile = getattr(self, 'destfile', 'test.jar')+ jaropts = getattr(self, 'jaropts', [])+ manifest = getattr(self, 'manifest', None)++ basedir = getattr(self, 'basedir', None)+ if basedir:+ if not isinstance(self.basedir, Node.Node):+ basedir = self.path.get_bld().make_node(basedir)+ else:+ basedir = self.path.get_bld()+ if not basedir:+ self.bld.fatal('Could not find the basedir %r for %r' % (self.basedir, self))++ self.jar_task = tsk = self.create_task('jar_create')+ if manifest:+ jarcreate = getattr(self, 'jarcreate', 'cfm')+ node = self.path.find_node(manifest)+ tsk.dep_nodes.append(node)+ jaropts.insert(0, node.abspath())+ else:+ jarcreate = getattr(self, 'jarcreate', 'cf')+ if not isinstance(destfile, Node.Node):+ destfile = self.path.find_or_declare(destfile)+ if not destfile:+ self.bld.fatal('invalid destfile %r for %r' % (destfile, self))+ tsk.set_outputs(destfile)+ tsk.basedir = basedir++ jaropts.append('-C')+ jaropts.append(basedir.bldpath())+ jaropts.append('.')++ tsk.env['JAROPTS'] = jaropts+ tsk.env['JARCREATE'] = jarcreate++ if getattr(self, 'javac_task', None):+ tsk.set_run_after(self.javac_task)++@feature('jar')+@after_method('jar_files')+def use_jar_files(self):+ """+ Process the *use* attribute to set the build order on the+ tasks created by another task generator.+ """+ lst = []+ self.uselib = self.to_list(getattr(self, 'uselib', []))+ names = self.to_list(getattr(self, 'use', []))+ get = self.bld.get_tgen_by_name+ for x in names:+ try:+ y = get(x)+ except Exception:+ self.uselib.append(x)+ else:+ y.post()+ self.jar_task.run_after.update(y.tasks)++class jar_create(Task.Task):+ """+ Create a jar file+ """+ color = 'GREEN'+ run_str = '${JAR} ${JARCREATE} ${TGT} ${JAROPTS}'++ def runnable_status(self):+ """+ Wait for dependent tasks to be executed, then read the+ files to update the list of inputs.+ """+ for t in self.run_after:+ if not t.hasrun:+ return Task.ASK_LATER+ if not self.inputs:+ global JAR_RE+ try:+ self.inputs = [x for x in self.basedir.ant_glob(JAR_RE, remove=False) if id(x) != id(self.outputs[0])]+ except Exception:+ raise Errors.WafError('Could not find the basedir %r for %r' % (self.basedir, self))+ return super(jar_create, self).runnable_status()++class javac(Task.Task):+ """+ Compile java files+ """+ color = 'BLUE'++ nocache = True+ """+ The .class files cannot be put into a cache at the moment+ """++ vars = ['CLASSPATH', 'JAVACFLAGS', 'JAVAC', 'OUTDIR']+ """+ The javac task will be executed again if the variables CLASSPATH, JAVACFLAGS, JAVAC or OUTDIR change.+ """++ def runnable_status(self):+ """+ Wait for dependent tasks to be complete, then read the file system to find the input nodes.+ """+ for t in self.run_after:+ if not t.hasrun:+ return Task.ASK_LATER++ if not self.inputs:+ global SOURCE_RE+ self.inputs = []+ for x in self.srcdir:+ self.inputs.extend(x.ant_glob(SOURCE_RE, remove=False))+ return super(javac, self).runnable_status()++ def run(self):+ """+ Execute the javac compiler+ """+ env = self.env+ gen = self.generator+ bld = gen.bld+ wd = bld.bldnode.abspath()+ def to_list(xx):+ if isinstance(xx, str): return [xx]+ return xx+ cmd = []+ cmd.extend(to_list(env['JAVAC']))+ cmd.extend(['-classpath'])+ cmd.extend(to_list(env['CLASSPATH']))+ cmd.extend(['-d'])+ cmd.extend(to_list(env['OUTDIR']))+ cmd.extend(to_list(env['JAVACFLAGS']))++ files = [a.path_from(bld.bldnode) for a in self.inputs]++ # workaround for command line length limit:+ # http://support.microsoft.com/kb/830473+ tmp = None+ try:+ if len(str(files)) + len(str(cmd)) > 8192:+ (fd, tmp) = tempfile.mkstemp(dir=bld.bldnode.abspath())+ try:+ os.write(fd, '\n'.join(files).encode())+ finally:+ if tmp:+ os.close(fd)+ if Logs.verbose:+ Logs.debug('runner: %r' % (cmd + files))+ cmd.append('@' + tmp)+ else:+ cmd += files++ ret = self.exec_command(cmd, cwd=wd, env=env.env or None)+ finally:+ if tmp:+ os.unlink(tmp)+ return ret++ def post_run(self):+ """+ """+ for n in self.generator.outdir.ant_glob('**/*.class'):+ n.sig = Utils.h_file(n.abspath()) # careful with this+ self.generator.bld.task_sigs[self.uid()] = self.cache_sig++@feature('javadoc')+@after_method('process_rule')+def create_javadoc(self):+ tsk = self.create_task('javadoc')+ tsk.classpath = getattr(self, 'classpath', [])+ self.javadoc_package = Utils.to_list(self.javadoc_package)+ if not isinstance(self.javadoc_output, Node.Node):+ self.javadoc_output = self.bld.path.find_or_declare(self.javadoc_output)++class javadoc(Task.Task):+ color = 'BLUE'++ def __str__(self):+ return '%s: %s -> %s\n' % (self.__class__.__name__, self.generator.srcdir, self.generator.javadoc_output)++ def run(self):+ env = self.env+ bld = self.generator.bld+ wd = bld.bldnode.abspath()++ #add src node + bld node (for generated java code)+ srcpath = self.generator.path.abspath() + os.sep + self.generator.srcdir+ srcpath += os.pathsep+ srcpath += self.generator.path.get_bld().abspath() + os.sep + self.generator.srcdir++ classpath = env.CLASSPATH+ classpath += os.pathsep+ classpath += os.pathsep.join(self.classpath)+ classpath = "".join(classpath)++ self.last_cmd = lst = []+ lst.extend(Utils.to_list(env['JAVADOC']))+ lst.extend(['-d', self.generator.javadoc_output.abspath()])+ lst.extend(['-sourcepath', srcpath])+ lst.extend(['-classpath', classpath])+ lst.extend(['-subpackages'])+ lst.extend(self.generator.javadoc_package)+ lst = [x for x in lst if x]++ self.generator.bld.cmd_and_log(lst, cwd=wd, env=env.env or None, quiet=0)++ def post_run(self):+ nodes = self.generator.javadoc_output.ant_glob('**')+ for x in nodes:+ x.sig = Utils.h_file(x.abspath())+ self.generator.bld.task_sigs[self.uid()] = self.cache_sig++def configure(self):+ """+ Detect the javac, java and jar programs+ """+ # If JAVA_PATH is set, we prepend it to the path list+ java_path = self.environ['PATH'].split(os.pathsep)+ v = self.env++ if 'JAVA_HOME' in self.environ:+ java_path = [os.path.join(self.environ['JAVA_HOME'], 'bin')] + java_path+ self.env['JAVA_HOME'] = [self.environ['JAVA_HOME']]++ for x in 'javac java jar javadoc'.split():+ self.find_program(x, var=x.upper(), path_list=java_path)+ self.env[x.upper()] = self.cmd_to_list(self.env[x.upper()])++ if 'CLASSPATH' in self.environ:+ v['CLASSPATH'] = self.environ['CLASSPATH']++ if not v['JAR']: self.fatal('jar is required for making java packages')+ if not v['JAVAC']: self.fatal('javac is required for compiling java classes')++ v['JARCREATE'] = 'cf' # can use cvf+ v['JAVACFLAGS'] = []++@conf+def check_java_class(self, classname, with_classpath=None):+ """+ Check if the specified java class exists++ :param classname: class to check, like java.util.HashMap+ :type classname: string+ :param with_classpath: additional classpath to give+ :type with_classpath: string+ """++ javatestdir = '.waf-javatest'++ classpath = javatestdir+ if self.env['CLASSPATH']:+ classpath += os.pathsep + self.env['CLASSPATH']+ if isinstance(with_classpath, str):+ classpath += os.pathsep + with_classpath++ shutil.rmtree(javatestdir, True)+ os.mkdir(javatestdir)++ java_file = open(os.path.join(javatestdir, 'Test.java'), 'w')+ java_file.write(class_check_source)+ java_file.close()++ # Compile the source+ self.exec_command(self.env['JAVAC'] + [os.path.join(javatestdir, 'Test.java')], shell=False)++ # Try to run the app+ cmd = self.env['JAVA'] + ['-cp', classpath, 'Test', classname]+ self.to_log("%s\n" % str(cmd))+ found = self.exec_command(cmd, shell=False)++ self.msg('Checking for java class %s' % classname, not found)++ shutil.rmtree(javatestdir, True)++ return found++@conf+def check_jni_headers(conf):+ """+ Check for jni headers and libraries. On success the conf.env variables xxx_JAVA are added for use in C/C++ targets::++ def options(opt):+ opt.load('compiler_c')++ def configure(conf):+ conf.load('compiler_c java')+ conf.check_jni_headers()++ def build(bld):+ bld.shlib(source='a.c', target='app', use='JAVA')+ """++ if not conf.env.CC_NAME and not conf.env.CXX_NAME:+ conf.fatal('load a compiler first (gcc, g++, ..)')++ if not conf.env.JAVA_HOME:+ conf.fatal('set JAVA_HOME in the system environment')++ # jni requires the jvm+ javaHome = conf.env['JAVA_HOME'][0]++ dir = conf.root.find_dir(conf.env.JAVA_HOME[0] + '/include')+ if dir is None:+ dir = conf.root.find_dir(conf.env.JAVA_HOME[0] + '/../Headers') # think different?!+ if dir is None:+ conf.fatal('JAVA_HOME does not seem to be set properly')++ f = dir.ant_glob('**/(jni|jni_md).h')+ incDirs = [x.parent.abspath() for x in f]++ dir = conf.root.find_dir(conf.env.JAVA_HOME[0])+ f = dir.ant_glob('**/*jvm.(so|dll|dylib)')+ libDirs = [x.parent.abspath() for x in f] or [javaHome]++ # On windows, we need both the .dll and .lib to link. On my JDK, they are+ # in different directories...+ f = dir.ant_glob('**/*jvm.(lib)')+ if f:+ libDirs = [[x, y.parent.abspath()] for x in libDirs for y in f]++ for d in libDirs:+ try:+ conf.check(header_name='jni.h', define_name='HAVE_JNI_H', lib='jvm',+ libpath=d, includes=incDirs, uselib_store='JAVA', uselib='JAVA')+ except Exception:+ pass+ else:+ break+ else:+ conf.fatal('could not find lib jvm in %r (see config.log)' % libDirs)++new file mode 100644@@ -0,0 +1,90 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+Support for the KDE4 libraries and msgfmt+"""++import os, sys, re+from waflib import Options, TaskGen, Task, Utils+from waflib.TaskGen import feature, after_method++@feature('msgfmt')+def apply_msgfmt(self):+ """+ Process all languages to create .mo files and to install them::++ def build(bld):+ bld(features='msgfmt', langs='es de fr', appname='myapp', install_path='${KDE4_LOCALE_INSTALL_DIR}')+ """+ for lang in self.to_list(self.langs):+ node = self.path.find_resource(lang+'.po')+ task = self.create_task('msgfmt', node, node.change_ext('.mo'))++ langname = lang.split('/')+ langname = langname[-1]++ inst = getattr(self, 'install_path', '${KDE4_LOCALE_INSTALL_DIR}')++ self.bld.install_as(+ inst + os.sep + langname + os.sep + 'LC_MESSAGES' + os.sep + getattr(self, 'appname', 'set_your_appname') + '.mo',+ task.outputs[0],+ chmod = getattr(self, 'chmod', Utils.O644))++class msgfmt(Task.Task):+ """+ Transform .po files into .mo files+ """+ color = 'BLUE'+ run_str = '${MSGFMT} ${SRC} -o ${TGT}'++def configure(self):+ """+ Detect kde4-config and set various variables for the *use* system::++ def options(opt):+ opt.load('compiler_cxx kde4')+ def configure(conf):+ conf.load('compiler_cxx kde4')+ def build(bld):+ bld.program(source='main.c', target='app', use='KDECORE KIO KHTML')+ """+ kdeconfig = self.find_program('kde4-config')+ prefix = self.cmd_and_log('%s --prefix' % kdeconfig).strip()+ fname = '%s/share/apps/cmake/modules/KDELibsDependencies.cmake' % prefix+ try: os.stat(fname)+ except OSError:+ fname = '%s/share/kde4/apps/cmake/modules/KDELibsDependencies.cmake' % prefix+ try: os.stat(fname)+ except OSError: self.fatal('could not open %s' % fname)++ try:+ txt = Utils.readf(fname)+ except (OSError, IOError):+ self.fatal('could not read %s' % fname)++ txt = txt.replace('\\\n', '\n')+ fu = re.compile('#(.*)\n')+ txt = fu.sub('', txt)++ setregexp = re.compile('([sS][eE][tT]\s*\()\s*([^\s]+)\s+\"([^"]+)\"\)')+ found = setregexp.findall(txt)++ for (_, key, val) in found:+ #print key, val+ self.env[key] = val++ # well well, i could just write an interpreter for cmake files+ self.env['LIB_KDECORE']= ['kdecore']+ self.env['LIB_KDEUI'] = ['kdeui']+ self.env['LIB_KIO'] = ['kio']+ self.env['LIB_KHTML'] = ['khtml']+ self.env['LIB_KPARTS'] = ['kparts']++ self.env['LIBPATH_KDECORE'] = [os.path.join(self.env.KDE4_LIB_INSTALL_DIR, 'kde4', 'devel'), self.env.KDE4_LIB_INSTALL_DIR]+ self.env['INCLUDES_KDECORE'] = [self.env['KDE4_INCLUDE_INSTALL_DIR']]+ self.env.append_value('INCLUDES_KDECORE', [self.env['KDE4_INCLUDE_INSTALL_DIR']+ os.sep + 'KDE'])++ self.find_program('msgfmt', var='MSGFMT')+new file mode 100644@@ -0,0 +1,59 @@+#!/usr/bin/env python+# encoding: utf-8+# Alex Rønne Petersen, 2012 (alexrp/Zor)++import sys+from waflib.Tools import ar, d+from waflib.Configure import conf++@conf+def find_ldc2(conf):+ """+ Find the program *ldc2* and set the variable *D*+ """++ conf.find_program(['ldc2'], var='D')++ out = conf.cmd_and_log([conf.env.D, '-version'])+ if out.find("based on DMD v2.") == -1:+ conf.fatal("detected compiler is not ldc2")++@conf+def common_flags_ldc2(conf):+ """+ Set the D flags required by *ldc2*+ """++ v = conf.env++ v['D_SRC_F'] = ['-c']+ v['D_TGT_F'] = '-of%s'++ v['D_LINKER'] = v['D']+ v['DLNK_SRC_F'] = ''+ v['DLNK_TGT_F'] = '-of%s'+ v['DINC_ST'] = '-I%s'++ v['DSHLIB_MARKER'] = v['DSTLIB_MARKER'] = ''+ v['DSTLIB_ST'] = v['DSHLIB_ST'] = '-L-l%s'+ v['DSTLIBPATH_ST'] = v['DLIBPATH_ST'] = '-L-L%s'++ v['LINKFLAGS_dshlib'] = ['-L-shared']++ v['DHEADER_ext'] = '.di'+ v['DFLAGS_d_with_header'] = ['-H', '-Hf']+ v['D_HDR_F'] = '%s'++ v['LINKFLAGS'] = []+ v['DFLAGS_dshlib'] = ['-relocation-model=pic']++def configure(conf):+ """+ Configuration for *ldc2*+ """++ conf.find_ldc2()+ conf.load('ar')+ conf.load('d')+ conf.common_flags_ldc2()+ conf.d_platform_flags()new file mode 100644@@ -0,0 +1,38 @@+#!/usr/bin/env python+# encoding: utf-8+# Sebastian Schlingmann, 2008+# Thomas Nagy, 2008-2010 (ita)++"""+Lua support.++Compile *.lua* files into *.luac*::++ def configure(conf):+ conf.load('lua')+ conf.env.LUADIR = '/usr/local/share/myapp/scripts/'+ def build(bld):+ bld(source='foo.lua')+"""++from waflib.TaskGen import extension+from waflib import Task, Utils++@extension('.lua')+def add_lua(self, node):+ tsk = self.create_task('luac', node, node.change_ext('.luac'))+ inst_to = getattr(self, 'install_path', self.env.LUADIR and '${LUADIR}' or None)+ if inst_to:+ self.bld.install_files(inst_to, tsk.outputs)+ return tsk++class luac(Task.Task):+ run_str = '${LUAC} -s -o ${TGT} ${SRC}'+ color = 'PINK'++def configure(conf):+ """+ Detect the luac compiler and set *conf.env.LUAC*+ """+ conf.find_program('luac', var='LUAC')+new file mode 100644@@ -0,0 +1,936 @@+#!/usr/bin/env python+# encoding: utf-8+# Carlos Rafael Giani, 2006 (dv)+# Tamas Pal, 2007 (folti)+# Nicolas Mercier, 2009++"""+Microsoft Visual C++/Intel C++ compiler support++Usage::++ $ waf configure --msvc_version="msvc 10.0,msvc 9.0" --msvc_target="x64"++or::++ def configure(conf):+ conf.env['MSVC_VERSIONS'] = ['msvc 10.0', 'msvc 9.0', 'msvc 8.0', 'msvc 7.1', 'msvc 7.0', 'msvc 6.0', 'wsdk 7.0', 'intel 11', 'PocketPC 9.0', 'Smartphone 8.0']+ conf.env['MSVC_TARGETS'] = ['x64']+ conf.load('msvc')++or::++ def configure(conf):+ conf.load('msvc', funs='no_autodetect')+ conf.check_lib_msvc('gdi32')+ conf.check_libs_msvc('kernel32 user32')+ def build(bld):+ tg = bld.program(source='main.c', target='app', use='KERNEL32 USER32 GDI32')++Platforms and targets will be tested in the order they appear;+the first good configuration will be used.+Supported platforms: ia64, x64, x86, x86_amd64, x86_ia64++Compilers supported:++* msvc => Visual Studio, versions 6.0 (VC 98, VC .NET 2002) to 10.0 (Visual Studio 2010)+* wsdk => Windows SDK, versions 6.0, 6.1, 7.0+* icl => Intel compiler, versions 9,10,11+* Smartphone => Compiler/SDK for Smartphone devices (armv4/v4i)+* PocketPC => Compiler/SDK for PocketPC devices (armv4/v4i)++To use WAF in a VS2008 Make file project (see http://code.google.com/p/waf/issues/detail?id=894)+You may consider to set the environment variable "VS_UNICODE_OUTPUT" to nothing before calling waf.+So in your project settings use something like 'cmd.exe /C "set VS_UNICODE_OUTPUT=& set PYTHONUNBUFFERED=true & waf build"'.+cmd.exe /C "chcp 1252 & set PYTHONUNBUFFERED=true && set && waf configure"+Setting PYTHONUNBUFFERED gives the unbuffered output.+"""++import os, sys, re, tempfile+from waflib import Utils, Task, Logs, Options+from waflib.Logs import debug, warn+from waflib.TaskGen import after_method, feature++from waflib.Configure import conf+from waflib.Tools import ccroot, c, cxx, ar, winres++g_msvc_systemlibs = '''+aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet+cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs+credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d+ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp+faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid+gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop+kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi+mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree+msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm+netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp+odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32+osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu+ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm+rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32+shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32+traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg+version vfw32 wbemuuid webpost wiaguid wininet winmm winscard winspool winstrm+wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp+'''.split()+"""importlibs provided by MSVC/Platform SDK. Do NOT search them"""++all_msvc_platforms = [ ('x64', 'amd64'), ('x86', 'x86'), ('ia64', 'ia64'), ('x86_amd64', 'amd64'), ('x86_ia64', 'ia64') ]+"""List of msvc platforms"""++all_wince_platforms = [ ('armv4', 'arm'), ('armv4i', 'arm'), ('mipsii', 'mips'), ('mipsii_fp', 'mips'), ('mipsiv', 'mips'), ('mipsiv_fp', 'mips'), ('sh4', 'sh'), ('x86', 'cex86') ]+"""List of wince platforms"""++all_icl_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'), ('Itanium', 'ia64')]+"""List of icl platforms"""++def options(opt):+ opt.add_option('--msvc_version', type='string', help = 'msvc version, eg: "msvc 10.0,msvc 9.0"', default='')+ opt.add_option('--msvc_targets', type='string', help = 'msvc targets, eg: "x64,arm"', default='')++def setup_msvc(conf, versions, arch = False):+ platforms = getattr(Options.options, 'msvc_targets', '').split(',')+ if platforms == ['']:+ platforms=Utils.to_list(conf.env['MSVC_TARGETS']) or [i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms]+ desired_versions = getattr(Options.options, 'msvc_version', '').split(',')+ if desired_versions == ['']:+ desired_versions = conf.env['MSVC_VERSIONS'] or [v for v,_ in versions][::-1]+ versiondict = dict(versions)++ for version in desired_versions:+ try:+ targets = dict(versiondict [version])+ for target in platforms:+ try:+ arch,(p1,p2,p3) = targets[target]+ compiler,revision = version.rsplit(' ', 1)+ if arch:+ return compiler,revision,p1,p2,p3,arch+ else:+ return compiler,revision,p1,p2,p3+ except KeyError: continue+ except KeyError: continue+ conf.fatal('msvc: Impossible to find a valid architecture for building (in setup_msvc)')++@conf+def get_msvc_version(conf, compiler, version, target, vcvars):+ """+ Create a bat file to obtain the location of the libraries++ :param compiler: ?+ :param version: ?+ :target: ?+ :vcvars: ?+ :return: the location of msvc, the location of include dirs, and the library paths+ :rtype: tuple of strings+ """+ debug('msvc: get_msvc_version: %r %r %r', compiler, version, target)+ batfile = conf.bldnode.make_node('waf-print-msvc.bat')+ batfile.write("""@echo off+set INCLUDE=+set LIB=+call "%s" %s+echo PATH=%%PATH%%+echo INCLUDE=%%INCLUDE%%+echo LIB=%%LIB%%+""" % (vcvars,target))+ sout = conf.cmd_and_log(['cmd', '/E:on', '/V:on', '/C', batfile.abspath()])+ lines = sout.splitlines()++ if not lines[0]:+ lines.pop(0)++ if version == '11.0':+ if lines[0].startswith('Error'):+ conf.fatal('msvc: Could not find a valid architecture for building (get_msvc_version_1)')+ else:+ for x in ('Setting environment', 'Setting SDK environment', 'Intel(R) C++ Compiler', 'Intel Parallel Studio'):+ if lines[0].find(x) > -1:+ lines.pop(0)+ break+ else:+ debug('msvc: get_msvc_version: %r %r %r -> not found', compiler, version, target)+ conf.fatal('msvc: Could not find a valid architecture for building (get_msvc_version_2)')++ MSVC_PATH = MSVC_INCDIR = MSVC_LIBDIR = None+ for line in lines:+ if line.startswith('PATH='):+ path = line[5:]+ MSVC_PATH = path.split(';')+ elif line.startswith('INCLUDE='):+ MSVC_INCDIR = [i for i in line[8:].split(';') if i]+ elif line.startswith('LIB='):+ MSVC_LIBDIR = [i for i in line[4:].split(';') if i]++ if None in (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR):+ conf.fatal('msvc: Could not find a valid architecture for building (get_msvc_version_3)')++ # Check if the compiler is usable at all.+ # The detection may return 64-bit versions even on 32-bit systems, and these would fail to run.+ env = dict(os.environ)+ env.update(PATH = path)+ compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler)+ cxx = conf.find_program(compiler_name, path_list=MSVC_PATH)+ cxx = conf.cmd_to_list(cxx)++ # delete CL if exists. because it could contain parameters wich can change cl's behaviour rather catastrophically.+ if 'CL' in env:+ del(env['CL'])++ try:+ try:+ conf.cmd_and_log(cxx + ['/help'], env=env)+ except Exception as e:+ debug('msvc: get_msvc_version: %r %r %r -> failure' % (compiler, version, target))+ debug(str(e))+ conf.fatal('msvc: cannot run the compiler (in get_msvc_version)')+ else:+ debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target)+ finally:+ conf.env[compiler_name] = ''++ return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR)++@conf+def gather_wsdk_versions(conf, versions):+ """+ Use winreg to add the msvc versions to the input list++ :param versions: list to modify+ :type versions: list+ """+ version_pattern = re.compile('^v..?.?\...?.?')+ try:+ all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows')+ except WindowsError:+ try:+ all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows')+ except WindowsError:+ return+ index = 0+ while 1:+ try:+ version = Utils.winreg.EnumKey(all_versions, index)+ except WindowsError:+ break+ index = index + 1+ if not version_pattern.match(version):+ continue+ try:+ msvc_version = Utils.winreg.OpenKey(all_versions, version)+ path,type = Utils.winreg.QueryValueEx(msvc_version,'InstallationFolder')+ except WindowsError:+ continue+ if os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')):+ targets = []+ for target,arch in all_msvc_platforms:+ try:+ targets.append((target, (arch, conf.get_msvc_version('wsdk', version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd')))))+ except conf.errors.ConfigurationError:+ pass+ versions.append(('wsdk ' + version[1:], targets))++def gather_wince_supported_platforms():+ """+ Checks SmartPhones SDKs++ :param versions: list to modify+ :type versions: list+ """+ supported_wince_platforms = []+ try:+ ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs')+ except WindowsError:+ try:+ ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs')+ except WindowsError:+ ce_sdk = ''+ if not ce_sdk:+ return supported_wince_platforms++ ce_index = 0+ while 1:+ try:+ sdk_device = Utils.winreg.EnumKey(ce_sdk, ce_index)+ except WindowsError:+ break+ ce_index = ce_index + 1+ sdk = Utils.winreg.OpenKey(ce_sdk, sdk_device)+ try:+ path,type = Utils.winreg.QueryValueEx(sdk, 'SDKRootDir')+ except WindowsError:+ try:+ path,type = Utils.winreg.QueryValueEx(sdk,'SDKInformation')+ path,xml = os.path.split(path)+ except WindowsError:+ continue+ path=str(path)+ path,device = os.path.split(path)+ if not device:+ path,device = os.path.split(path)+ for arch,compiler in all_wince_platforms:+ platforms = []+ if os.path.isdir(os.path.join(path, device, 'Lib', arch)):+ platforms.append((arch, compiler, os.path.join(path, device, 'Include', arch), os.path.join(path, device, 'Lib', arch)))+ if platforms:+ supported_wince_platforms.append((device, platforms))+ return supported_wince_platforms++def gather_msvc_detected_versions():+ #Detected MSVC versions!+ version_pattern = re.compile('^(\d\d?\.\d\d?)(Exp)?$')+ detected_versions = []+ for vcver,vcvar in [('VCExpress','Exp'), ('VisualStudio','')]:+ try:+ prefix = 'SOFTWARE\\Wow6432node\\Microsoft\\'+vcver+ all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix)+ except WindowsError:+ try:+ prefix = 'SOFTWARE\\Microsoft\\'+vcver+ all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix)+ except WindowsError:+ continue++ index = 0+ while 1:+ try:+ version = Utils.winreg.EnumKey(all_versions, index)+ except WindowsError:+ break+ index = index + 1+ match = version_pattern.match(version)+ if not match:+ continue+ else:+ versionnumber = float(match.group(1))+ detected_versions.append((versionnumber, version+vcvar, prefix+"\\"+version))+ def fun(tup):+ return tup[0]++ detected_versions.sort(key = fun)+ return detected_versions++@conf+def gather_msvc_targets(conf, versions, version, vc_path):+ #Looking for normal MSVC compilers!+ targets = []+ if os.path.isfile(os.path.join(vc_path, 'vcvarsall.bat')):+ for target,realtarget in all_msvc_platforms[::-1]:+ try:+ targets.append((target, (realtarget, conf.get_msvc_version('msvc', version, target, os.path.join(vc_path, 'vcvarsall.bat')))))+ except conf.errors.ConfigurationError:+ pass+ elif os.path.isfile(os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')):+ try:+ targets.append(('x86', ('x86', conf.get_msvc_version('msvc', version, 'x86', os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')))))+ except conf.errors.ConfigurationError:+ pass+ elif os.path.isfile(os.path.join(vc_path, 'Bin', 'vcvars32.bat')):+ try:+ targets.append(('x86', ('x86', conf.get_msvc_version('msvc', version, '', os.path.join(vc_path, 'Bin', 'vcvars32.bat')))))+ except conf.errors.ConfigurationError:+ pass+ versions.append(('msvc '+ version, targets))++@conf+def gather_wince_targets(conf, versions, version, vc_path, vsvars, supported_platforms):+ #Looking for Win CE compilers!+ for device,platforms in supported_platforms:+ cetargets = []+ for platform,compiler,include,lib in platforms:+ winCEpath = os.path.join(vc_path, 'ce')+ if not os.path.isdir(winCEpath):+ continue+ try:+ common_bindirs,_1,_2 = conf.get_msvc_version('msvc', version, 'x86', vsvars)+ except conf.errors.ConfigurationError:+ continue+ if os.path.isdir(os.path.join(winCEpath, 'lib', platform)):+ bindirs = [os.path.join(winCEpath, 'bin', compiler), os.path.join(winCEpath, 'bin', 'x86_'+compiler)] + common_bindirs+ incdirs = [os.path.join(winCEpath, 'include'), os.path.join(winCEpath, 'atlmfc', 'include'), include]+ libdirs = [os.path.join(winCEpath, 'lib', platform), os.path.join(winCEpath, 'atlmfc', 'lib', platform), lib]+ cetargets.append((platform, (platform, (bindirs,incdirs,libdirs))))+ if cetargets:+ versions.append((device + ' ' + version, cetargets))++@conf+def gather_msvc_versions(conf, versions):+ vc_paths = []+ for (v,version,reg) in gather_msvc_detected_versions():+ try:+ try:+ msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\VC")+ except WindowsError:+ msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\Microsoft Visual C++")+ path,type = Utils.winreg.QueryValueEx(msvc_version, 'ProductDir')+ vc_paths.append((version, os.path.abspath(str(path))))+ except WindowsError:+ continue++ wince_supported_platforms = gather_wince_supported_platforms()++ for version,vc_path in vc_paths:+ vs_path = os.path.dirname(vc_path)+ vsvars = os.path.join(vs_path, 'Common7', 'Tools', 'vsvars32.bat')+ if wince_supported_platforms and os.path.isfile(vsvars):+ conf.gather_wince_targets(versions, version, vc_path, vsvars, wince_supported_platforms)++ for version,vc_path in vc_paths:+ vs_path = os.path.dirname(vc_path)+ conf.gather_msvc_targets(versions, version, vc_path)++@conf+def gather_icl_versions(conf, versions):+ """+ Checks ICL compilers++ :param versions: list to modify+ :type versions: list+ """+ version_pattern = re.compile('^...?.?\....?.?')+ try:+ all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++')+ except WindowsError:+ try:+ all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Compilers\\C++')+ except WindowsError:+ return+ index = 0+ while 1:+ try:+ version = Utils.winreg.EnumKey(all_versions, index)+ except WindowsError:+ break+ index = index + 1+ if not version_pattern.match(version):+ continue+ targets = []+ for target,arch in all_icl_platforms:+ try:+ if target=='intel64': targetDir='EM64T_NATIVE'+ else: targetDir=target+ Utils.winreg.OpenKey(all_versions,version+'\\'+targetDir)+ icl_version=Utils.winreg.OpenKey(all_versions,version)+ path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir')+ if os.path.isfile(os.path.join(path,'bin','iclvars.bat')):+ try:+ targets.append((target,(arch,conf.get_msvc_version('intel',version,target,os.path.join(path,'bin','iclvars.bat')))))+ except conf.errors.ConfigurationError:+ pass+ except WindowsError:+ pass+ for target,arch in all_icl_platforms:+ try:+ icl_version = Utils.winreg.OpenKey(all_versions, version+'\\'+target)+ path,type = Utils.winreg.QueryValueEx(icl_version,'ProductDir')+ if os.path.isfile(os.path.join(path, 'bin', 'iclvars.bat')):+ try:+ targets.append((target, (arch, conf.get_msvc_version('intel', version, target, os.path.join(path, 'bin', 'iclvars.bat')))))+ except conf.errors.ConfigurationError:+ pass+ except WindowsError:+ continue+ major = version[0:2]+ versions.append(('intel ' + major, targets))++@conf+def get_msvc_versions(conf):+ """+ :return: list of compilers installed+ :rtype: list of string+ """+ if not conf.env['MSVC_INSTALLED_VERSIONS']:+ lst = []+ conf.gather_icl_versions(lst)+ conf.gather_wsdk_versions(lst)+ conf.gather_msvc_versions(lst)+ conf.env['MSVC_INSTALLED_VERSIONS'] = lst+ return conf.env['MSVC_INSTALLED_VERSIONS']++@conf+def print_all_msvc_detected(conf):+ """+ Print the contents of *conf.env.MSVC_INSTALLED_VERSIONS*+ """+ for version,targets in conf.env['MSVC_INSTALLED_VERSIONS']:+ Logs.info(version)+ for target,l in targets:+ Logs.info("\t"+target)++@conf+def detect_msvc(conf, arch = False):+ versions = get_msvc_versions(conf)+ return setup_msvc(conf, versions, arch)++@conf+def find_lt_names_msvc(self, libname, is_static=False):+ """+ Win32/MSVC specific code to glean out information from libtool la files.+ this function is not attached to the task_gen class+ """+ lt_names=[+ 'lib%s.la' % libname,+ '%s.la' % libname,+ ]++ for path in self.env['LIBPATH']:+ for la in lt_names:+ laf=os.path.join(path,la)+ dll=None+ if os.path.exists(laf):+ ltdict = Utils.read_la_file(laf)+ lt_libdir=None+ if ltdict.get('libdir', ''):+ lt_libdir = ltdict['libdir']+ if not is_static and ltdict.get('library_names', ''):+ dllnames=ltdict['library_names'].split()+ dll=dllnames[0].lower()+ dll=re.sub('\.dll$', '', dll)+ return (lt_libdir, dll, False)+ elif ltdict.get('old_library', ''):+ olib=ltdict['old_library']+ if os.path.exists(os.path.join(path,olib)):+ return (path, olib, True)+ elif lt_libdir != '' and os.path.exists(os.path.join(lt_libdir,olib)):+ return (lt_libdir, olib, True)+ else:+ return (None, olib, True)+ else:+ raise self.errors.WafError('invalid libtool object file: %s' % laf)+ return (None, None, None)++@conf+def libname_msvc(self, libname, is_static=False):+ lib = libname.lower()+ lib = re.sub('\.lib$','',lib)++ if lib in g_msvc_systemlibs:+ return lib++ lib=re.sub('^lib','',lib)++ if lib == 'm':+ return None++ (lt_path, lt_libname, lt_static) = self.find_lt_names_msvc(lib, is_static)++ if lt_path != None and lt_libname != None:+ if lt_static == True:+ # file existance check has been made by find_lt_names+ return os.path.join(lt_path,lt_libname)++ if lt_path != None:+ _libpaths=[lt_path] + self.env['LIBPATH']+ else:+ _libpaths=self.env['LIBPATH']++ static_libs=[+ 'lib%ss.lib' % lib,+ 'lib%s.lib' % lib,+ '%ss.lib' % lib,+ '%s.lib' %lib,+ ]++ dynamic_libs=[+ 'lib%s.dll.lib' % lib,+ 'lib%s.dll.a' % lib,+ '%s.dll.lib' % lib,+ '%s.dll.a' % lib,+ 'lib%s_d.lib' % lib,+ '%s_d.lib' % lib,+ '%s.lib' %lib,+ ]++ libnames=static_libs+ if not is_static:+ libnames=dynamic_libs + static_libs++ for path in _libpaths:+ for libn in libnames:+ if os.path.exists(os.path.join(path, libn)):+ debug('msvc: lib found: %s' % os.path.join(path,libn))+ return re.sub('\.lib$', '',libn)++ #if no lib can be found, just return the libname as msvc expects it+ self.fatal("The library %r could not be found" % libname)+ return re.sub('\.lib$', '', libname)++@conf+def check_lib_msvc(self, libname, is_static=False, uselib_store=None):+ """+ Ideally we should be able to place the lib in the right env var, either STLIB or LIB,+ but we don't distinguish static libs from shared libs.+ This is ok since msvc doesn't have any special linker flag to select static libs (no env['STLIB_MARKER'])+ """+ libn = self.libname_msvc(libname, is_static)++ if not uselib_store:+ uselib_store = libname.upper()++ if False and is_static: # disabled+ self.env['STLIB_' + uselib_store] = [libn]+ else:+ self.env['LIB_' + uselib_store] = [libn]++@conf+def check_libs_msvc(self, libnames, is_static=False):+ for libname in Utils.to_list(libnames):+ self.check_lib_msvc(libname, is_static)++def configure(conf):+ """+ Configuration methods to call for detecting msvc+ """+ conf.autodetect(True)+ conf.find_msvc()+ conf.msvc_common_flags()+ conf.cc_load_tools()+ conf.cxx_load_tools()+ conf.cc_add_flags()+ conf.cxx_add_flags()+ conf.link_add_flags()+ conf.visual_studio_add_flags()++@conf+def no_autodetect(conf):+ conf.env.NO_MSVC_DETECT = 1+ configure(conf)++@conf+def autodetect(conf, arch = False):+ v = conf.env+ if v.NO_MSVC_DETECT:+ return+ if arch:+ compiler, version, path, includes, libdirs, arch = conf.detect_msvc(True)+ v['DEST_CPU'] = arch+ else:+ compiler, version, path, includes, libdirs = conf.detect_msvc()++ v['PATH'] = path+ v['INCLUDES'] = includes+ v['LIBPATH'] = libdirs+ v['MSVC_COMPILER'] = compiler+ try:+ v['MSVC_VERSION'] = float(version)+ except Exception:+ v['MSVC_VERSION'] = float(version[:-3])++def _get_prog_names(conf, compiler):+ if compiler=='intel':+ compiler_name = 'ICL'+ linker_name = 'XILINK'+ lib_name = 'XILIB'+ else:+ # assumes CL.exe+ compiler_name = 'CL'+ linker_name = 'LINK'+ lib_name = 'LIB'+ return compiler_name, linker_name, lib_name++@conf+def find_msvc(conf):+ """Due to path format limitations, limit operation only to native Win32. Yeah it sucks."""+ if sys.platform == 'cygwin':+ conf.fatal('MSVC module does not work under cygwin Python!')++ # the autodetection is supposed to be performed before entering in this method+ v = conf.env+ path = v['PATH']+ compiler = v['MSVC_COMPILER']+ version = v['MSVC_VERSION']++ compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler)+ v.MSVC_MANIFEST = (compiler == 'msvc' and version >= 8) or (compiler == 'wsdk' and version >= 6) or (compiler == 'intel' and version >= 11)++ # compiler+ cxx = None+ if v['CXX']: cxx = v['CXX']+ elif 'CXX' in conf.environ: cxx = conf.environ['CXX']+ cxx = conf.find_program(compiler_name, var='CXX', path_list=path)+ cxx = conf.cmd_to_list(cxx)++ # before setting anything, check if the compiler is really msvc+ env = dict(conf.environ)+ if path: env.update(PATH = ';'.join(path))+ if not conf.cmd_and_log(cxx + ['/nologo', '/help'], env=env):+ conf.fatal('the msvc compiler could not be identified')++ # c/c++ compiler+ v['CC'] = v['CXX'] = cxx+ v['CC_NAME'] = v['CXX_NAME'] = 'msvc'++ # linker+ if not v['LINK_CXX']:+ link = conf.find_program(linker_name, path_list=path)+ if link: v['LINK_CXX'] = link+ else: conf.fatal('%s was not found (linker)' % linker_name)+ v['LINK'] = link++ if not v['LINK_CC']:+ v['LINK_CC'] = v['LINK_CXX']++ # staticlib linker+ if not v['AR']:+ stliblink = conf.find_program(lib_name, path_list=path, var='AR')+ if not stliblink: return+ v['ARFLAGS'] = ['/NOLOGO']++ # manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later+ if v.MSVC_MANIFEST:+ conf.find_program('MT', path_list=path, var='MT')+ v['MTFLAGS'] = ['/NOLOGO']++ conf.load('winres')++ if not conf.env['WINRC']:+ warn('Resource compiler not found. Compiling resource file is disabled')++@conf+def visual_studio_add_flags(self):+ """visual studio flags found in the system environment"""+ v = self.env+ try: v.prepend_value('INCLUDES', [x for x in self.environ['INCLUDE'].split(';') if x]) # notice the 'S'+ except Exception: pass+ try: v.prepend_value('LIBPATH', [x for x in self.environ['LIB'].split(';') if x])+ except Exception: pass++@conf+def msvc_common_flags(conf):+ """+ Setup the flags required for executing the msvc compiler+ """+ v = conf.env++ v['DEST_BINFMT'] = 'pe'+ v.append_value('CFLAGS', ['/nologo'])+ v.append_value('CXXFLAGS', ['/nologo'])+ v['DEFINES_ST'] = '/D%s'++ v['CC_SRC_F'] = ''+ v['CC_TGT_F'] = ['/c', '/Fo']+ if v['MSVC_VERSION'] >= 8:+ v['CC_TGT_F']= ['/FC'] + v['CC_TGT_F']+ v['CXX_SRC_F'] = ''+ v['CXX_TGT_F'] = ['/c', '/Fo']+ if v['MSVC_VERSION'] >= 8:+ v['CXX_TGT_F']= ['/FC'] + v['CXX_TGT_F']++ v['CPPPATH_ST'] = '/I%s' # template for adding include paths++ v['AR_TGT_F'] = v['CCLNK_TGT_F'] = v['CXXLNK_TGT_F'] = '/OUT:'++ # Subsystem specific flags+ v['CFLAGS_CONSOLE'] = v['CXXFLAGS_CONSOLE'] = ['/SUBSYSTEM:CONSOLE']+ v['CFLAGS_NATIVE'] = v['CXXFLAGS_NATIVE'] = ['/SUBSYSTEM:NATIVE']+ v['CFLAGS_POSIX'] = v['CXXFLAGS_POSIX'] = ['/SUBSYSTEM:POSIX']+ v['CFLAGS_WINDOWS'] = v['CXXFLAGS_WINDOWS'] = ['/SUBSYSTEM:WINDOWS']+ v['CFLAGS_WINDOWSCE'] = v['CXXFLAGS_WINDOWSCE'] = ['/SUBSYSTEM:WINDOWSCE']++ # CRT specific flags+ v['CFLAGS_CRT_MULTITHREADED'] = v['CXXFLAGS_CRT_MULTITHREADED'] = ['/MT']+ v['CFLAGS_CRT_MULTITHREADED_DLL'] = v['CXXFLAGS_CRT_MULTITHREADED_DLL'] = ['/MD']++ v['CFLAGS_CRT_MULTITHREADED_DBG'] = v['CXXFLAGS_CRT_MULTITHREADED_DBG'] = ['/MTd']+ v['CFLAGS_CRT_MULTITHREADED_DLL_DBG'] = v['CXXFLAGS_CRT_MULTITHREADED_DLL_DBG'] = ['/MDd']++ # linker+ v['LIB_ST'] = '%s.lib' # template for adding shared libs+ v['LIBPATH_ST'] = '/LIBPATH:%s' # template for adding libpaths+ v['STLIB_ST'] = '%s.lib'+ v['STLIBPATH_ST'] = '/LIBPATH:%s'++ v.append_value('LINKFLAGS', ['/NOLOGO'])+ if v['MSVC_MANIFEST']:+ v.append_value('LINKFLAGS', ['/MANIFEST'])++ # shared library+ v['CFLAGS_cshlib'] = []+ v['CXXFLAGS_cxxshlib'] = []+ v['LINKFLAGS_cshlib'] = v['LINKFLAGS_cxxshlib'] = ['/DLL']+ v['cshlib_PATTERN'] = v['cxxshlib_PATTERN'] = '%s.dll'+ v['implib_PATTERN'] = '%s.lib'+ v['IMPLIB_ST'] = '/IMPLIB:%s'++ # static library+ v['LINKFLAGS_cstlib'] = []+ v['cstlib_PATTERN'] = v['cxxstlib_PATTERN'] = '%s.lib'++ # program+ v['cprogram_PATTERN'] = v['cxxprogram_PATTERN'] = '%s.exe'+++#######################################################################################################+##### conf above, build below++@after_method('apply_link')+@feature('c', 'cxx')+def apply_flags_msvc(self):+ """+ Add additional flags implied by msvc, such as subsystems and pdb files::++ def build(bld):+ bld.stlib(source='main.c', target='bar', subsystem='gruik')+ """+ if self.env.CC_NAME != 'msvc' or not getattr(self, 'link_task', None):+ return++ is_static = isinstance(self.link_task, ccroot.stlink_task)++ subsystem = getattr(self, 'subsystem', '')+ if subsystem:+ subsystem = '/subsystem:%s' % subsystem+ flags = is_static and 'ARFLAGS' or 'LINKFLAGS'+ self.env.append_value(flags, subsystem)++ if not is_static:+ for f in self.env.LINKFLAGS:+ d = f.lower()+ if d[1:] == 'debug':+ pdbnode = self.link_task.outputs[0].change_ext('.pdb')+ self.link_task.outputs.append(pdbnode)++ try:+ self.install_task.source.append(pdbnode)+ except AttributeError:+ pass++ break++# split the manifest file processing from the link task, like for the rc processing++@feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib')+@after_method('apply_link')+def apply_manifest(self):+ """+ Special linker for MSVC with support for embedding manifests into DLL's+ and executables compiled by Visual Studio 2005 or probably later. Without+ the manifest file, the binaries are unusable.+ See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx+ """++ if self.env.CC_NAME == 'msvc' and self.env.MSVC_MANIFEST and getattr(self, 'link_task', None):+ out_node = self.link_task.outputs[0]+ man_node = out_node.parent.find_or_declare(out_node.name + '.manifest')+ self.link_task.outputs.append(man_node)+ self.link_task.do_manifest = True++def exec_mf(self):+ """+ Create the manifest file+ """+ env = self.env+ mtool = env['MT']+ if not mtool:+ return 0++ self.do_manifest = False++ outfile = self.outputs[0].abspath()++ manifest = None+ for out_node in self.outputs:+ if out_node.name.endswith('.manifest'):+ manifest = out_node.abspath()+ break+ if manifest is None:+ # Should never get here. If we do, it means the manifest file was+ # never added to the outputs list, thus we don't have a manifest file+ # to embed, so we just return.+ return 0++ # embedding mode. Different for EXE's and DLL's.+ # see: http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx+ mode = ''+ if 'cprogram' in self.generator.features or 'cxxprogram' in self.generator.features:+ mode = '1'+ elif 'cshlib' in self.generator.features or 'cxxshlib' in self.generator.features:+ mode = '2'++ debug('msvc: embedding manifest in mode %r' % mode)++ lst = []+ lst.append(env['MT'])+ lst.extend(Utils.to_list(env['MTFLAGS']))+ lst.extend(['-manifest', manifest])+ lst.append('-outputresource:%s;%s' % (outfile, mode))++ lst = [lst]+ return self.exec_command(*lst)++def quote_response_command(self, flag):+ if flag.find(' ') > -1:+ for x in ('/LIBPATH:', '/IMPLIB:', '/OUT:', '/I'):+ if flag.startswith(x):+ flag = '%s"%s"' % (x, flag[len(x):])+ break+ else:+ flag = '"%s"' % flag+ return flag++def exec_response_command(self, cmd, **kw):+ # not public yet+ try:+ tmp = None+ if sys.platform.startswith('win') and isinstance(cmd, list) and len(' '.join(cmd)) >= 8192:+ program = cmd[0] #unquoted program name, otherwise exec_command will fail+ cmd = [self.quote_response_command(x) for x in cmd]+ (fd, tmp) = tempfile.mkstemp()+ os.write(fd, '\r\n'.join(i.replace('\\', '\\\\') for i in cmd[1:]).encode())+ os.close(fd)+ cmd = [program, '@' + tmp]+ # no return here, that's on purpose+ ret = self.generator.bld.exec_command(cmd, **kw)+ finally:+ if tmp:+ try:+ os.remove(tmp)+ except OSError:+ pass # anti-virus and indexers can keep the files open -_-+ return ret++########## stupid evil command modification: concatenate the tokens /Fx, /doc, and /x: with the next token++def exec_command_msvc(self, *k, **kw):+ """+ Change the command-line execution for msvc programs.+ Instead of quoting all the paths and keep using the shell, we can just join the options msvc is interested in+ """+ if self.env['CC_NAME'] == 'msvc':+ if isinstance(k[0], list):+ lst = []+ carry = ''+ for a in k[0]:+ if a == '/Fo' or a == '/doc' or a[-1] == ':':+ carry = a+ else:+ lst.append(carry + a)+ carry = ''+ k = [lst]++ if self.env['PATH']:+ env = dict(self.env.env or os.environ)+ env.update(PATH = ';'.join(self.env['PATH']))+ kw['env'] = env++ bld = self.generator.bld+ try:+ if not kw.get('cwd', None):+ kw['cwd'] = bld.cwd+ except AttributeError:+ bld.cwd = kw['cwd'] = bld.variant_dir++ ret = self.exec_response_command(k[0], **kw)+ if not ret and getattr(self, 'do_manifest', None):+ ret = self.exec_mf()+ return ret++for k in 'c cxx cprogram cxxprogram cshlib cxxshlib cstlib cxxstlib'.split():+ cls = Task.classes.get(k, None)+ if cls:+ cls.exec_command = exec_command_msvc+ cls.exec_response_command = exec_response_command+ cls.quote_response_command = quote_response_command+ cls.exec_mf = exec_mf+new file mode 100644@@ -0,0 +1,24 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2008-2010 (ita)++"""+Nasm tool (asm processing)+"""++import waflib.Tools.asm # leave this+from waflib.TaskGen import feature++@feature('asm')+def apply_nasm_vars(self):+ """provided for compatibility"""+ self.env.append_value('ASFLAGS', self.to_list(getattr(self, 'nasm_flags', [])))++def configure(conf):+ """+ Detect nasm/yasm and set the variable *AS*+ """+ nasm = conf.find_program(['nasm', 'yasm'], var='AS')+ conf.env.AS_TGT_F = ['-o']+ conf.env.ASLNK_TGT_F = ['-o']+ conf.load('asm')new file mode 100644@@ -0,0 +1,157 @@+#!/usr/bin/env python+# encoding: utf-8+# andersg at 0x63.nu 2007+# Thomas Nagy 2010 (ita)++"""+Support for Perl extensions. A C/C++ compiler is required::++ def options(opt):+ opt.load('compiler_c perl')+ def configure(conf):+ conf.load('compiler_c perl')+ conf.check_perl_version((5,6,0))+ conf.check_perl_ext_devel()+ conf.check_perl_module('Cairo')+ conf.check_perl_module('Devel::PPPort 4.89')+ def build(bld):+ bld(+ features = 'c cshlib perlext',+ source = 'Mytest.xs',+ target = 'Mytest',+ install_path = '${ARCHDIR_PERL}/auto')+ bld.install_files('${ARCHDIR_PERL}', 'Mytest.pm')+"""++import os+from waflib import Task, Options, Utils+from waflib.Configure import conf+from waflib.TaskGen import extension, feature, before_method++@before_method('apply_incpaths', 'apply_link', 'propagate_uselib_vars')+@feature('perlext')+def init_perlext(self):+ """+ Change the values of *cshlib_PATTERN* and *cxxshlib_PATTERN* to remove the+ *lib* prefix from library names.+ """+ self.uselib = self.to_list(getattr(self, 'uselib', []))+ if not 'PERLEXT' in self.uselib: self.uselib.append('PERLEXT')+ self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['perlext_PATTERN']++@extension('.xs')+def xsubpp_file(self, node):+ """+ Create :py:class:`waflib.Tools.perl.xsubpp` tasks to process *.xs* files+ """+ outnode = node.change_ext('.c')+ self.create_task('xsubpp', node, outnode)+ self.source.append(outnode)++class xsubpp(Task.Task):+ """+ Process *.xs* files+ """+ run_str = '${PERL} ${XSUBPP} -noprototypes -typemap ${EXTUTILS_TYPEMAP} ${SRC} > ${TGT}'+ color = 'BLUE'+ ext_out = ['.h']++@conf+def check_perl_version(self, minver=None):+ """+ Check if Perl is installed, and set the variable PERL.+ minver is supposed to be a tuple+ """+ res = True+ + if minver:+ cver = '.'.join(map(str,minver))+ else:+ cver = ''++ self.start_msg('Checking for minimum perl version %s' % cver)++ perl = getattr(Options.options, 'perlbinary', None)++ if not perl:+ perl = self.find_program('perl', var='PERL')+ + if not perl:+ self.end_msg("Perl not found", color="YELLOW")+ return False+ + self.env['PERL'] = perl++ version = self.cmd_and_log([perl, "-e", 'printf \"%vd\", $^V'])+ if not version:+ res = False+ version = "Unknown"+ elif not minver is None:+ ver = tuple(map(int, version.split(".")))+ if ver < minver:+ res = False++ self.end_msg(version, color=res and "GREEN" or "YELLOW")+ return res++@conf+def check_perl_module(self, module):+ """+ Check if specified perlmodule is installed.++ The minimum version can be specified by specifying it after modulename+ like this::++ def configure(conf):+ conf.check_perl_module("Some::Module 2.92")+ """+ cmd = [self.env['PERL'], '-e', 'use %s' % module]+ self.start_msg('perl module %s' % module)+ try:+ r = self.cmd_and_log(cmd)+ except Exception:+ self.end_msg(False)+ return None+ self.end_msg(r or True)+ return r++@conf+def check_perl_ext_devel(self):+ """+ Check for configuration needed to build perl extensions.++ Sets different xxx_PERLEXT variables in the environment.++ Also sets the ARCHDIR_PERL variable useful as installation path,+ which can be overridden by ``--with-perl-archdir`` option.+ """++ env = self.env+ perl = env.PERL+ if not perl:+ self.fatal('find perl first')++ def read_out(cmd):+ return Utils.to_list(self.cmd_and_log(perl + cmd))++ env['LINKFLAGS_PERLEXT'] = read_out(" -MConfig -e'print $Config{lddlflags}'")+ env['INCLUDES_PERLEXT'] = read_out(" -MConfig -e'print \"$Config{archlib}/CORE\"'")+ env['CFLAGS_PERLEXT'] = read_out(" -MConfig -e'print \"$Config{ccflags} $Config{cccdlflags}\"'")++ env['XSUBPP'] = read_out(" -MConfig -e'print \"$Config{privlib}/ExtUtils/xsubpp$Config{exe_ext}\"'")+ env['EXTUTILS_TYPEMAP'] = read_out(" -MConfig -e'print \"$Config{privlib}/ExtUtils/typemap\"'")++ if not getattr(Options.options, 'perlarchdir', None):+ env['ARCHDIR_PERL'] = self.cmd_and_log(perl + " -MConfig -e'print $Config{sitearch}'")+ else:+ env['ARCHDIR_PERL'] = getattr(Options.options, 'perlarchdir')++ env['perlext_PATTERN'] = '%s.' + self.cmd_and_log(perl + " -MConfig -e'print $Config{dlext}'")++def options(opt):+ """+ Add the ``--with-perl-archdir`` and ``--with-perl-binary`` command-line options.+ """+ opt.add_option('--with-perl-binary', type='string', dest='perlbinary', help = 'Specify alternate perl binary', default=None)+ opt.add_option('--with-perl-archdir', type='string', dest='perlarchdir', help = 'Specify directory where to install arch specific files', default=None)+new file mode 100644@@ -0,0 +1,534 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2007-2010 (ita)+# Gustavo Carneiro (gjc), 2007++"""+Support for Python, detect the headers and libraries and provide+*use* variables to link C/C++ programs against them::++ def options(opt):+ opt.load('compiler_c python')+ def configure(conf):+ conf.load('compiler_c python')+ conf.check_python_version((2,4,2))+ conf.check_python_headers()+ def build(bld):+ bld.program(features='pyembed', source='a.c', target='myprog')+ bld.shlib(features='pyext', source='b.c', target='mylib')+"""++import os, sys+from waflib import Utils, Options, Errors, Logs+from waflib.TaskGen import extension, before_method, after_method, feature+from waflib.Configure import conf++FRAG = '''+#include <Python.h>+#ifdef __cplusplus+extern "C" {+#endif+ void Py_Initialize(void);+ void Py_Finalize(void);+#ifdef __cplusplus+}+#endif+int main(int argc, char **argv)+{+ (void)argc; (void)argv;+ Py_Initialize();+ Py_Finalize();+ return 0;+}+'''+"""+Piece of C/C++ code used in :py:func:`waflib.Tools.python.check_python_headers`+"""++INST = '''+import sys, py_compile+py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3])+'''+"""+Piece of Python code used in :py:func:`waflib.Tools.python.install_pyfile` for installing python files+"""++DISTUTILS_IMP = ['from distutils.sysconfig import get_config_var, get_python_lib']++@extension('.py')+def process_py(self, node):+ """+ Add a callback using :py:func:`waflib.Tools.python.install_pyfile` to install a python file+ """+ try:+ if not self.bld.is_install:+ return+ except AttributeError:+ return++ try:+ if not self.install_path:+ return+ except AttributeError:+ self.install_path = '${PYTHONDIR}'++ # i wonder now why we wanted to do this after the build is over+ # issue #901: people want to preserve the structure of installed files+ def inst_py(ctx):+ install_from = getattr(self, 'install_from', None)+ if install_from:+ install_from = self.path.find_dir(install_from)+ install_pyfile(self, node, install_from)+ self.bld.add_post_fun(inst_py)++def install_pyfile(self, node, install_from=None):+ """+ Execute the installation of a python file++ :param node: python file+ :type node: :py:class:`waflib.Node.Node`+ """++ from_node = install_from or node.parent+ tsk = self.bld.install_as(self.install_path + '/' + node.path_from(from_node), node, postpone=False)+ path = tsk.get_install_path()++ if self.bld.is_install < 0:+ Logs.info("+ removing byte compiled python files")+ for x in 'co':+ try:+ os.remove(path + x)+ except OSError:+ pass++ if self.bld.is_install > 0:+ try:+ st1 = os.stat(path)+ except OSError:+ Logs.error('The python file is missing, this should not happen')++ for x in ['c', 'o']:+ do_inst = self.env['PY' + x.upper()]+ try:+ st2 = os.stat(path + x)+ except OSError:+ pass+ else:+ if st1.st_mtime <= st2.st_mtime:+ do_inst = False++ if do_inst:+ lst = (x == 'o') and [self.env['PYFLAGS_OPT']] or []+ (a, b, c) = (path, path + x, tsk.get_install_path(destdir=False) + x)+ argv = self.env['PYTHON'] + lst + ['-c', INST, a, b, c]+ Logs.info('+ byte compiling %r' % (path + x))+ env = self.env.env or None+ ret = Utils.subprocess.Popen(argv, env=env).wait()+ if ret:+ raise Errors.WafError('py%s compilation failed %r' % (x, path))++@feature('py')+def feature_py(self):+ """+ Dummy feature which does nothing+ """+ pass++@feature('pyext')+@before_method('propagate_uselib_vars', 'apply_link')+@after_method('apply_bundle')+def init_pyext(self):+ """+ Change the values of *cshlib_PATTERN* and *cxxshlib_PATTERN* to remove the+ *lib* prefix from library names.+ """+ self.uselib = self.to_list(getattr(self, 'uselib', []))+ if not 'PYEXT' in self.uselib:+ self.uselib.append('PYEXT')+ # override shlib_PATTERN set by the osx module+ self.env.cshlib_PATTERN = self.env.cxxshlib_PATTERN = self.env.macbundle_PATTERN = self.env.pyext_PATTERN+ self.env.fcshlib_PATTERN = self.env.dshlib_PATTERN = self.env.pyext_PATTERN++ try:+ if not self.install_path:+ return+ except AttributeError:+ self.install_path = '${PYTHONARCHDIR}'++@feature('pyext')+@before_method('apply_link', 'apply_bundle')+def set_bundle(self):+ if Utils.unversioned_sys_platform() == 'darwin':+ self.mac_bundle = True++@before_method('propagate_uselib_vars')+@feature('pyembed')+def init_pyembed(self):+ """+ Add the PYEMBED variable.+ """+ self.uselib = self.to_list(getattr(self, 'uselib', []))+ if not 'PYEMBED' in self.uselib:+ self.uselib.append('PYEMBED')++@conf+def get_python_variables(self, variables, imports=None):+ """+ Spawn a new python process to dump configuration variables++ :param variables: variables to print+ :type variables: list of string+ :param imports: one import by element+ :type imports: list of string+ :return: the variable values+ :rtype: list of string+ """+ if not imports:+ try:+ imports = self.python_imports+ except AttributeError:+ imports = DISTUTILS_IMP++ program = list(imports) # copy+ program.append('')+ for v in variables:+ program.append("print(repr(%s))" % v)+ os_env = dict(os.environ)+ try:+ del os_env['MACOSX_DEPLOYMENT_TARGET'] # see comments in the OSX tool+ except KeyError:+ pass++ try:+ out = self.cmd_and_log(self.env.PYTHON + ['-c', '\n'.join(program)], env=os_env)+ except Errors.WafError:+ self.fatal('The distutils module is unusable: install "python-devel"?')+ self.to_log(out)+ return_values = []+ for s in out.split('\n'):+ s = s.strip()+ if not s:+ continue+ if s == 'None':+ return_values.append(None)+ elif (s[0] == "'" and s[-1] == "'") or (s[0] == '"' and s[-1] == '"'):+ return_values.append(eval(s))+ elif s[0].isdigit():+ return_values.append(int(s))+ else: break+ return return_values++@conf+def check_python_headers(conf):+ """+ Check for headers and libraries necessary to extend or embed python by using the module *distutils*.+ On success the environment variables xxx_PYEXT and xxx_PYEMBED are added:++ * PYEXT: for compiling python extensions+ * PYEMBED: for embedding a python interpreter+ """++ # FIXME rewrite++ env = conf.env+ if not env['CC_NAME'] and not env['CXX_NAME']:+ conf.fatal('load a compiler first (gcc, g++, ..)')++ if not env['PYTHON_VERSION']:+ conf.check_python_version()++ pybin = conf.env.PYTHON+ if not pybin:+ conf.fatal('Could not find the python executable')++ v = 'prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS'.split()+ try:+ lst = conf.get_python_variables(["get_config_var('%s') or ''" % x for x in v])+ except RuntimeError:+ conf.fatal("Python development headers not found (-v for details).")++ vals = ['%s = %r' % (x, y) for (x, y) in zip(v, lst)]+ conf.to_log("Configuration returned from %r:\n%r\n" % (pybin, '\n'.join(vals)))++ dct = dict(zip(v, lst))+ x = 'MACOSX_DEPLOYMENT_TARGET'+ if dct[x]:+ conf.env[x] = conf.environ[x] = dct[x]++ env['pyext_PATTERN'] = '%s' + dct['SO'] # not a mistake++ # Check for python libraries for embedding++ all_flags = dct['LDFLAGS'] + ' ' + dct['CFLAGS']+ conf.parse_flags(all_flags, 'PYEMBED')++ all_flags = dct['LDFLAGS'] + ' ' + dct['LDSHARED'] + ' ' + dct['CFLAGS']+ conf.parse_flags(all_flags, 'PYEXT')++ result = None+ #name = 'python' + env['PYTHON_VERSION']++ # TODO simplify this+ for name in ('python' + env['PYTHON_VERSION'], 'python' + env['PYTHON_VERSION'].replace('.', '')):++ # LIBPATH_PYEMBED is already set; see if it works.+ if not result and env['LIBPATH_PYEMBED']:+ path = env['LIBPATH_PYEMBED']+ conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path)+ result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBPATH_PYEMBED' % name)++ if not result and dct['LIBDIR']:+ path = [dct['LIBDIR']]+ conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path)+ result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBDIR' % name)++ if not result and dct['LIBPL']:+ path = [dct['LIBPL']]+ conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n")+ result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in python_LIBPL' % name)++ if not result:+ path = [os.path.join(dct['prefix'], "libs")]+ conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n")+ result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in $prefix/libs' % name)++ if result:+ break # do not forget to set LIBPATH_PYEMBED++ if result:+ env['LIBPATH_PYEMBED'] = path+ env.append_value('LIB_PYEMBED', [name])+ else:+ conf.to_log("\n\n### LIB NOT FOUND\n")++ # under certain conditions, python extensions must link to+ # python libraries, not just python embedding programs.+ if (Utils.is_win32 or sys.platform.startswith('os2')+ or dct['Py_ENABLE_SHARED']):+ env['LIBPATH_PYEXT'] = env['LIBPATH_PYEMBED']+ env['LIB_PYEXT'] = env['LIB_PYEMBED']++ # We check that pythonX.Y-config exists, and if it exists we+ # use it to get only the includes, else fall back to distutils.+ num = '.'.join(env['PYTHON_VERSION'].split('.')[:2])+ conf.find_program([''.join(pybin) + '-config', 'python%s-config' % num, 'python-config-%s' % num, 'python%sm-config' % num], var='PYTHON_CONFIG', mandatory=False)++ includes = []+ if conf.env.PYTHON_CONFIG:+ for incstr in conf.cmd_and_log([ conf.env.PYTHON_CONFIG, '--includes']).strip().split():+ # strip the -I or /I+ if (incstr.startswith('-I') or incstr.startswith('/I')):+ incstr = incstr[2:]+ # append include path, unless already given+ if incstr not in includes:+ includes.append(incstr)+ conf.to_log("Include path for Python extensions (found via python-config --includes): %r\n" % (includes,))+ env['INCLUDES_PYEXT'] = includes+ env['INCLUDES_PYEMBED'] = includes+ else:+ conf.to_log("Include path for Python extensions "+ "(found via distutils module): %r\n" % (dct['INCLUDEPY'],))+ env['INCLUDES_PYEXT'] = [dct['INCLUDEPY']]+ env['INCLUDES_PYEMBED'] = [dct['INCLUDEPY']]++ # Code using the Python API needs to be compiled with -fno-strict-aliasing+ if env['CC_NAME'] == 'gcc':+ env.append_value('CFLAGS_PYEMBED', ['-fno-strict-aliasing'])+ env.append_value('CFLAGS_PYEXT', ['-fno-strict-aliasing'])+ if env['CXX_NAME'] == 'gcc':+ env.append_value('CXXFLAGS_PYEMBED', ['-fno-strict-aliasing'])+ env.append_value('CXXFLAGS_PYEXT', ['-fno-strict-aliasing'])++ if env.CC_NAME == "msvc":+ from distutils.msvccompiler import MSVCCompiler+ dist_compiler = MSVCCompiler()+ dist_compiler.initialize()+ env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options)+ env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options)+ env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared)++ # See if it compiles+ try:+ conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H',+ uselib='PYEMBED', fragment=FRAG,+ errmsg=':-(')+ except conf.errors.ConfigurationError:+ # python3.2, oh yeah+ xx = conf.env.CXX_NAME and 'cxx' or 'c'+ conf.check_cfg(msg='Asking python-config for the flags (pyembed)',+ path=conf.env.PYTHON_CONFIG, package='', uselib_store='PYEMBED', args=['--cflags', '--libs', '--ldflags'])+ conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H', msg='Getting pyembed flags from python-config',+ fragment=FRAG, errmsg='Could not build a python embedded interpreter',+ features='%s %sprogram pyembed' % (xx, xx))+ conf.check_cfg(msg='Asking python-config for the flags (pyext)',+ path=conf.env.PYTHON_CONFIG, package='', uselib_store='PYEXT', args=['--cflags', '--libs', '--ldflags'])+ conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H', msg='Getting pyext flags from python-config',+ features='%s %sshlib pyext' % (xx, xx), fragment=FRAG, errmsg='Could not build python extensions')++@conf+def check_python_version(conf, minver=None):+ """+ Check if the python interpreter is found matching a given minimum version.+ minver should be a tuple, eg. to check for python >= 2.4.2 pass (2,4,2) as minver.++ If successful, PYTHON_VERSION is defined as 'MAJOR.MINOR'+ (eg. '2.4') of the actual python version found, and PYTHONDIR is+ defined, pointing to the site-packages directory appropriate for+ this python version, where modules/packages/extensions should be+ installed.++ :param minver: minimum version+ :type minver: tuple of int+ """+ assert minver is None or isinstance(minver, tuple)+ pybin = conf.env['PYTHON']+ if not pybin:+ conf.fatal('could not find the python executable')++ # Get python version string+ cmd = pybin + ['-c', 'import sys\nfor x in sys.version_info: print(str(x))']+ Logs.debug('python: Running python command %r' % cmd)+ lines = conf.cmd_and_log(cmd).split()+ assert len(lines) == 5, "found %i lines, expected 5: %r" % (len(lines), lines)+ pyver_tuple = (int(lines[0]), int(lines[1]), int(lines[2]), lines[3], int(lines[4]))++ # compare python version with the minimum required+ result = (minver is None) or (pyver_tuple >= minver)++ if result:+ # define useful environment variables+ pyver = '.'.join([str(x) for x in pyver_tuple[:2]])+ conf.env['PYTHON_VERSION'] = pyver++ if 'PYTHONDIR' in conf.environ:+ pydir = conf.environ['PYTHONDIR']+ else:+ if Utils.is_win32:+ (python_LIBDEST, pydir) = conf.get_python_variables(+ ["get_config_var('LIBDEST') or ''",+ "get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']])+ else:+ python_LIBDEST = None+ (pydir,) = conf.get_python_variables( ["get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']])+ if python_LIBDEST is None:+ if conf.env['LIBDIR']:+ python_LIBDEST = os.path.join(conf.env['LIBDIR'], "python" + pyver)+ else:+ python_LIBDEST = os.path.join(conf.env['PREFIX'], "lib", "python" + pyver)+++ if 'PYTHONARCHDIR' in conf.environ:+ pyarchdir = conf.environ['PYTHONARCHDIR']+ else:+ (pyarchdir, ) = conf.get_python_variables( ["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r) or ''" % conf.env['PREFIX']])+ if not pyarchdir:+ pyarchdir = pydir++ if hasattr(conf, 'define'): # conf.define is added by the C tool, so may not exist+ conf.define('PYTHONDIR', pydir)+ conf.define('PYTHONARCHDIR', pyarchdir)++ conf.env['PYTHONDIR'] = pydir+ conf.env['PYTHONARCHDIR'] = pyarchdir++ # Feedback+ pyver_full = '.'.join(map(str, pyver_tuple[:3]))+ if minver is None:+ conf.msg('Checking for python version', pyver_full)+ else:+ minver_str = '.'.join(map(str, minver))+ conf.msg('Checking for python version', pyver_tuple, ">= %s" % (minver_str,) and 'GREEN' or 'YELLOW')++ if not result:+ conf.fatal('The python version is too old, expecting %r' % (minver,))++PYTHON_MODULE_TEMPLATE = '''+import %s as current_module+version = getattr(current_module, '__version__', None)+if version is not None:+ print(str(version))+else:+ print('unknown version')+'''++@conf+def check_python_module(conf, module_name, condition=''):+ """+ Check if the selected python interpreter can import the given python module::++ def configure(conf):+ conf.check_python_module('pygccxml')+ conf.check_python_module('re', condition="ver > num(2, 0, 4) and ver <= num(3, 0, 0)")++ :param module_name: module+ :type module_name: string+ """+ msg = 'Python module %s' % module_name+ if condition:+ msg = '%s (%s)' % (msg, condition)+ conf.start_msg(msg)+ try:+ ret = conf.cmd_and_log(conf.env['PYTHON'] + ['-c', PYTHON_MODULE_TEMPLATE % module_name])+ except Exception:+ conf.end_msg(False)+ conf.fatal('Could not find the python module %r' % module_name)++ ret = ret.strip()+ if condition:+ conf.end_msg(ret)+ if ret == 'unknown version':+ conf.fatal('Could not check the %s version' % module_name)++ from distutils.version import LooseVersion+ def num(*k):+ if isinstance(k[0], int):+ return LooseVersion('.'.join([str(x) for x in k]))+ else:+ return LooseVersion(k[0])+ d = {'num': num, 'ver': LooseVersion(ret)}+ ev = eval(condition, {}, d)+ if not ev:+ conf.fatal('The %s version does not satisfy the requirements' % module_name)+ else:+ if ret == 'unknown version':+ conf.end_msg(True)+ else:+ conf.end_msg(ret)++def configure(conf):+ """+ Detect the python interpreter+ """+ try:+ conf.find_program('python', var='PYTHON')+ except conf.errors.ConfigurationError:+ Logs.warn("could not find a python executable, setting to sys.executable '%s'" % sys.executable)+ conf.env.PYTHON = sys.executable++ if conf.env.PYTHON != sys.executable:+ Logs.warn("python executable %r differs from system %r" % (conf.env.PYTHON, sys.executable))+ conf.env.PYTHON = conf.cmd_to_list(conf.env.PYTHON)++ v = conf.env+ v['PYCMD'] = '"import sys, py_compile;py_compile.compile(sys.argv[1], sys.argv[2])"'+ v['PYFLAGS'] = ''+ v['PYFLAGS_OPT'] = '-O'++ v['PYC'] = getattr(Options.options, 'pyc', 1)+ v['PYO'] = getattr(Options.options, 'pyo', 1)++def options(opt):+ """+ Add the options ``--nopyc`` and ``--nopyo``+ """+ opt.add_option('--nopyc',+ action='store_false',+ default=1,+ help = 'Do not install bytecode compiled .pyc files (configuration) [Default:install]',+ dest = 'pyc')+ opt.add_option('--nopyo',+ action='store_false',+ default=1,+ help='Do not install optimised compiled .pyo files (configuration) [Default:install]',+ dest='pyo')+new file mode 100644@@ -0,0 +1,685 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""++Tool Description+================++This tool helps with finding Qt4 tools and libraries,+and also provides syntactic sugar for using Qt4 tools.++The following snippet illustrates the tool usage::++ def options(opt):+ opt.load('compiler_cxx qt4')++ def configure(conf):+ conf.load('compiler_cxx qt4')++ def build(bld):+ bld(+ features = 'qt4 cxx cxxprogram',+ uselib = 'QTCORE QTGUI QTOPENGL QTSVG',+ source = 'main.cpp textures.qrc aboutDialog.ui',+ target = 'window',+ )++Here, the UI description and resource files will be processed+to generate code.++Usage+=====++Load the "qt4" tool.++You also need to edit your sources accordingly:++- the normal way of doing things is to have your C++ files+ include the .moc file.+ This is regarded as the best practice (and provides much faster+ compilations).+ It also implies that the include paths have beenset properly.++- to have the include paths added automatically, use the following::++ from waflib.TaskGen import feature, before_method, after_method+ @feature('cxx')+ @after_method('process_source')+ @before_method('apply_incpaths')+ def add_includes_paths(self):+ incs = set(self.to_list(getattr(self, 'includes', '')))+ for x in self.compiled_tasks:+ incs.add(x.inputs[0].parent.path_from(self.path))+ self.includes = list(incs)++Note: another tool provides Qt processing that does not require+.moc includes, see ``playground/slow_qt/``self.++A few options (--qt{dir,bin,...}) and environment variables+(QT4_{ROOT,DIR,MOC,UIC,XCOMPILE}) allow finer tuning of the tool,+tool path selection, etc; please read the source for more info.++"""++try:+ from xml.sax import make_parser+ from xml.sax.handler import ContentHandler+except ImportError:+ has_xml = False+ ContentHandler = object+else:+ has_xml = True++import os, sys+from waflib.Tools import c_preproc, cxx+from waflib import Task, Utils, Options, Errors+from waflib.TaskGen import feature, after_method, extension+from waflib.Configure import conf+from waflib import Logs++MOC_H = ['.h', '.hpp', '.hxx', '.hh']+"""+File extensions associated to the .moc files+"""++EXT_RCC = ['.qrc']+"""+File extension for the resource (.qrc) files+"""++EXT_UI = ['.ui']+"""+File extension for the user interface (.ui) files+"""++EXT_QT4 = ['.cpp', '.cc', '.cxx', '.C']+"""+File extensions of C++ files that may require a .moc processing+"""++QT4_LIBS = "QtCore QtGui QtUiTools QtNetwork QtOpenGL QtSql QtSvg QtTest QtXml QtXmlPatterns QtWebKit Qt3Support QtHelp QtScript QtDeclarative"++class qxx(cxx.cxx):+ """+ Each C++ file can have zero or several .moc files to create.+ They are known only when the files are scanned (preprocessor)+ To avoid scanning the c++ files each time (parsing C/C++), the results+ are retrieved from the task cache (bld.node_deps/bld.raw_deps).+ The moc tasks are also created *dynamically* during the build.+ """++ def __init__(self, *k, **kw):+ Task.Task.__init__(self, *k, **kw)+ self.moc_done = 0++ def scan(self):+ """Re-use the C/C++ scanner, but remove the moc files from the dependencies"""+ (nodes, names) = c_preproc.scan(self)+ # for some reasons (variants) the moc node may end in the list of node deps+ for x in nodes:+ if x.name.endswith('.moc'):+ nodes.remove(x)+ names.append(x.path_from(self.inputs[0].parent.get_bld()))+ return (nodes, names)++ def runnable_status(self):+ """+ Compute the task signature to make sure the scanner was executed. Create the+ moc tasks by using :py:meth:`waflib.Tools.qt4.qxx.add_moc_tasks` (if necessary),+ then postpone the task execution (there is no need to recompute the task signature).+ """+ if self.moc_done:+ return Task.Task.runnable_status(self)+ else:+ for t in self.run_after:+ if not t.hasrun:+ return Task.ASK_LATER+ self.add_moc_tasks()+ return Task.Task.runnable_status(self)++ def add_moc_tasks(self):+ """+ Create the moc tasks by looking in ``bld.raw_deps[self.uid()]``+ """+ node = self.inputs[0]+ bld = self.generator.bld++ try:+ # compute the signature once to know if there is a moc file to create+ self.signature()+ except KeyError:+ # the moc file may be referenced somewhere else+ pass+ else:+ # remove the signature, it must be recomputed with the moc task+ delattr(self, 'cache_sig')++ moctasks=[]+ mocfiles=[]+ try:+ tmp_lst = bld.raw_deps[self.uid()]+ bld.raw_deps[self.uid()] = []+ except KeyError:+ tmp_lst = []+ for d in tmp_lst:+ if not d.endswith('.moc'):+ continue+ # paranoid check+ if d in mocfiles:+ Logs.error("paranoia owns")+ continue+ # process that base.moc only once+ mocfiles.append(d)++ # find the extension - this search is done only once++ h_node = None+ try: ext = Options.options.qt_header_ext.split()+ except AttributeError: pass+ if not ext: ext = MOC_H++ base2 = d[:-4]+ for x in [node.parent] + self.generator.includes_nodes:+ for e in ext:+ h_node = x.find_node(base2 + e)+ if h_node:+ break+ if h_node:+ m_node = h_node.change_ext('.moc')+ break+ else:+ for k in EXT_QT4:+ if base2.endswith(k):+ for x in [node.parent] + self.generator.includes_nodes:+ h_node = x.find_node(base2)+ if h_node:+ break+ if h_node:+ m_node = h_node.change_ext(k + '.moc')+ break+ if not h_node:+ raise Errors.WafError('no header found for %r which is a moc file' % d)++ # next time we will not search for the extension (look at the 'for' loop below)+ bld.node_deps[(self.inputs[0].parent.abspath(), m_node.name)] = h_node++ # create the task+ task = Task.classes['moc'](env=self.env, generator=self.generator)+ task.set_inputs(h_node)+ task.set_outputs(m_node)++ # direct injection in the build phase (safe because called from the main thread)+ gen = bld.producer+ gen.outstanding.insert(0, task)+ gen.total += 1++ moctasks.append(task)++ # remove raw deps except the moc files to save space (optimization)+ tmp_lst = bld.raw_deps[self.uid()] = mocfiles++ # look at the file inputs, it is set right above+ lst = bld.node_deps.get(self.uid(), ())+ for d in lst:+ name = d.name+ if name.endswith('.moc'):+ task = Task.classes['moc'](env=self.env, generator=self.generator)+ task.set_inputs(bld.node_deps[(self.inputs[0].parent.abspath(), name)]) # 1st element in a tuple+ task.set_outputs(d)++ gen = bld.producer+ gen.outstanding.insert(0, task)+ gen.total += 1++ moctasks.append(task)++ # simple scheduler dependency: run the moc task before others+ self.run_after.update(set(moctasks))+ self.moc_done = 1++ run = Task.classes['cxx'].__dict__['run']++class trans_update(Task.Task):+ """Update a .ts files from a list of C++ files"""+ run_str = '${QT_LUPDATE} ${SRC} -ts ${TGT}'+ color = 'BLUE'+Task.update_outputs(trans_update)++class XMLHandler(ContentHandler):+ """+ Parser for *.qrc* files+ """+ def __init__(self):+ self.buf = []+ self.files = []+ def startElement(self, name, attrs):+ if name == 'file':+ self.buf = []+ def endElement(self, name):+ if name == 'file':+ self.files.append(str(''.join(self.buf)))+ def characters(self, cars):+ self.buf.append(cars)++@extension(*EXT_RCC)+def create_rcc_task(self, node):+ "Create rcc and cxx tasks for *.qrc* files"+ rcnode = node.change_ext('_rc.cpp')+ rcctask = self.create_task('rcc', node, rcnode)+ cpptask = self.create_task('cxx', rcnode, rcnode.change_ext('.o'))+ try:+ self.compiled_tasks.append(cpptask)+ except AttributeError:+ self.compiled_tasks = [cpptask]+ return cpptask++@extension(*EXT_UI)+def create_uic_task(self, node):+ "hook for uic tasks"+ uictask = self.create_task('ui4', node)+ uictask.outputs = [self.path.find_or_declare(self.env['ui_PATTERN'] % node.name[:-3])]++@extension('.ts')+def add_lang(self, node):+ """add all the .ts file into self.lang"""+ self.lang = self.to_list(getattr(self, 'lang', [])) + [node]++@feature('qt4')+@after_method('apply_link')+def apply_qt4(self):+ """+ Add MOC_FLAGS which may be necessary for moc::++ def build(bld):+ bld.program(features='qt4', source='main.cpp', target='app', use='QTCORE')++ The additional parameters are:++ :param lang: list of translation files (\*.ts) to process+ :type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension+ :param update: whether to process the C++ files to update the \*.ts files (use **waf --translate**)+ :type update: bool+ :param langname: if given, transform the \*.ts files into a .qrc files to include in the binary file+ :type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension+ """+ if getattr(self, 'lang', None):+ qmtasks = []+ for x in self.to_list(self.lang):+ if isinstance(x, str):+ x = self.path.find_resource(x + '.ts')+ qmtasks.append(self.create_task('ts2qm', x, x.change_ext('.qm')))++ if getattr(self, 'update', None) and Options.options.trans_qt4:+ cxxnodes = [a.inputs[0] for a in self.compiled_tasks] + [+ a.inputs[0] for a in self.tasks if getattr(a, 'inputs', None) and a.inputs[0].name.endswith('.ui')]+ for x in qmtasks:+ self.create_task('trans_update', cxxnodes, x.inputs)++ if getattr(self, 'langname', None):+ qmnodes = [x.outputs[0] for x in qmtasks]+ rcnode = self.langname+ if isinstance(rcnode, str):+ rcnode = self.path.find_or_declare(rcnode + '.qrc')+ t = self.create_task('qm2rcc', qmnodes, rcnode)+ k = create_rcc_task(self, t.outputs[0])+ self.link_task.inputs.append(k.outputs[0])++ lst = []+ for flag in self.to_list(self.env['CXXFLAGS']):+ if len(flag) < 2: continue+ f = flag[0:2]+ if f in ['-D', '-I', '/D', '/I']:+ if (f[0] == '/'):+ lst.append('-' + flag[1:])+ else:+ lst.append(flag)+ self.env['MOC_FLAGS'] = lst++@extension(*EXT_QT4)+def cxx_hook(self, node):+ """+ Re-map C++ file extensions to the :py:class:`waflib.Tools.qt4.qxx` task.+ """+ return self.create_compiled_task('qxx', node)++class rcc(Task.Task):+ """+ Process *.qrc* files+ """+ color = 'BLUE'+ run_str = '${QT_RCC} -name ${SRC[0].name} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}'+ ext_out = ['.h']++ def scan(self):+ """Parse the *.qrc* files"""+ node = self.inputs[0]++ if not has_xml:+ Logs.error('no xml support was found, the rcc dependencies will be incomplete!')+ return ([], [])++ parser = make_parser()+ curHandler = XMLHandler()+ parser.setContentHandler(curHandler)+ fi = open(self.inputs[0].abspath(), 'r')+ try:+ parser.parse(fi)+ finally:+ fi.close()++ nodes = []+ names = []+ root = self.inputs[0].parent+ for x in curHandler.files:+ nd = root.find_resource(x)+ if nd: nodes.append(nd)+ else: names.append(x)+ return (nodes, names)++class moc(Task.Task):+ """+ Create *.moc* files+ """+ color = 'BLUE'+ run_str = '${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}'++class ui4(Task.Task):+ """+ Process *.ui* files+ """+ color = 'BLUE'+ run_str = '${QT_UIC} ${SRC} -o ${TGT}'+ ext_out = ['.h']++class ts2qm(Task.Task):+ """+ Create *.qm* files from *.ts* files+ """+ color = 'BLUE'+ run_str = '${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}'++class qm2rcc(Task.Task):+ """+ Transform *.qm* files into *.rc* files+ """+ color = 'BLUE'+ after = 'ts2qm'++ def run(self):+ """Create a qrc file including the inputs"""+ txt = '\n'.join(['<file>%s</file>' % k.path_from(self.outputs[0].parent) for k in self.inputs])+ code = '<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n%s\n</qresource>\n</RCC>' % txt+ self.outputs[0].write(code)++def configure(self):+ """+ Besides the configuration options, the environment variable QT4_ROOT may be used+ to give the location of the qt4 libraries (absolute path).++ The detection will use the program *pkg-config* through :py:func:`waflib.Tools.config_c.check_cfg`+ """+ self.find_qt4_binaries()+ self.set_qt4_libs_to_check()+ self.find_qt4_libraries()+ self.add_qt4_rpath()+ self.simplify_qt4_libs()++@conf+def find_qt4_binaries(self):+ env = self.env+ opt = Options.options++ qtdir = getattr(opt, 'qtdir', '')+ qtbin = getattr(opt, 'qtbin', '')++ paths = []++ if qtdir:+ qtbin = os.path.join(qtdir, 'bin')++ # the qt directory has been given from QT4_ROOT - deduce the qt binary path+ if not qtdir:+ qtdir = os.environ.get('QT4_ROOT', '')+ qtbin = os.environ.get('QT4_BIN', None) or os.path.join(qtdir, 'bin')++ if qtbin:+ paths = [qtbin]++ # no qtdir, look in the path and in /usr/local/Trolltech+ if not qtdir:+ paths = os.environ.get('PATH', '').split(os.pathsep)+ paths.append('/usr/share/qt4/bin/')+ try:+ lst = Utils.listdir('/usr/local/Trolltech/')+ except OSError:+ pass+ else:+ if lst:+ lst.sort()+ lst.reverse()++ # keep the highest version+ qtdir = '/usr/local/Trolltech/%s/' % lst[0]+ qtbin = os.path.join(qtdir, 'bin')+ paths.append(qtbin)++ # at the end, try to find qmake in the paths given+ # keep the one with the highest version+ cand = None+ prev_ver = ['4', '0', '0']+ for qmk in ['qmake-qt4', 'qmake4', 'qmake']:+ try:+ qmake = self.find_program(qmk, path_list=paths)+ except self.errors.ConfigurationError:+ pass+ else:+ try:+ version = self.cmd_and_log([qmake, '-query', 'QT_VERSION']).strip()+ except self.errors.WafError:+ pass+ else:+ if version:+ new_ver = version.split('.')+ if new_ver > prev_ver:+ cand = qmake+ prev_ver = new_ver+ if cand:+ self.env.QMAKE = cand+ else:+ self.fatal('Could not find qmake for qt4')++ qtbin = self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_BINS']).strip() + os.sep++ def find_bin(lst, var):+ if var in env:+ return+ for f in lst:+ try:+ ret = self.find_program(f, path_list=paths)+ except self.errors.ConfigurationError:+ pass+ else:+ env[var]=ret+ break++ find_bin(['uic-qt3', 'uic3'], 'QT_UIC3')+ find_bin(['uic-qt4', 'uic'], 'QT_UIC')+ if not env['QT_UIC']:+ self.fatal('cannot find the uic compiler for qt4')++ try:+ uicver = self.cmd_and_log(env['QT_UIC'] + " -version 2>&1").strip()+ except self.errors.ConfigurationError:+ self.fatal('this uic compiler is for qt3, add uic for qt4 to your path')+ uicver = uicver.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt', '')+ self.msg('Checking for uic version', '%s' % uicver)+ if uicver.find(' 3.') != -1:+ self.fatal('this uic compiler is for qt3, add uic for qt4 to your path')++ find_bin(['moc-qt4', 'moc'], 'QT_MOC')+ find_bin(['rcc'], 'QT_RCC')+ find_bin(['lrelease-qt4', 'lrelease'], 'QT_LRELEASE')+ find_bin(['lupdate-qt4', 'lupdate'], 'QT_LUPDATE')++ env['UIC3_ST']= '%s -o %s'+ env['UIC_ST'] = '%s -o %s'+ env['MOC_ST'] = '-o'+ env['ui_PATTERN'] = 'ui_%s.h'+ env['QT_LRELEASE_FLAGS'] = ['-silent']+ env.MOCCPPPATH_ST = '-I%s'+ env.MOCDEFINES_ST = '-D%s'++@conf+def find_qt4_libraries(self):+ qtlibs = getattr(Options.options, 'qtlibs', None) or os.environ.get("QT4_LIBDIR", None)+ if not qtlibs:+ try:+ qtlibs = self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_LIBS']).strip()+ except Errors.WafError:+ qtdir = self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_PREFIX']).strip() + os.sep+ qtlibs = os.path.join(qtdir, 'lib')+ self.msg('Found the Qt4 libraries in', qtlibs)++ qtincludes = os.environ.get("QT4_INCLUDES", None) or self.cmd_and_log([self.env.QMAKE, '-query', 'QT_INSTALL_HEADERS']).strip()+ env = self.env+ if not 'PKG_CONFIG_PATH' in os.environ:+ os.environ['PKG_CONFIG_PATH'] = '%s:%s/pkgconfig:/usr/lib/qt4/lib/pkgconfig:/opt/qt4/lib/pkgconfig:/usr/lib/qt4/lib:/opt/qt4/lib' % (qtlibs, qtlibs)++ try:+ if os.environ.get("QT4_XCOMPILE", None):+ raise self.errors.ConfigurationError()+ self.check_cfg(atleast_pkgconfig_version='0.1')+ except self.errors.ConfigurationError:+ for i in self.qt4_vars:+ uselib = i.upper()+ if Utils.unversioned_sys_platform() == "darwin":+ # Since at least qt 4.7.3 each library locates in separate directory+ frameworkName = i + ".framework"+ qtDynamicLib = os.path.join(qtlibs, frameworkName, i)+ if os.path.exists(qtDynamicLib):+ env.append_unique('FRAMEWORK_' + uselib, i)+ self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN')+ else:+ self.msg('Checking for %s' % i, False, 'YELLOW')+ env.append_unique('INCLUDES_' + uselib, os.path.join(qtlibs, frameworkName, 'Headers'))+ elif env.DEST_OS != "win32":+ qtDynamicLib = os.path.join(qtlibs, "lib" + i + ".so")+ qtStaticLib = os.path.join(qtlibs, "lib" + i + ".a")+ if os.path.exists(qtDynamicLib):+ env.append_unique('LIB_' + uselib, i)+ self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN')+ elif os.path.exists(qtStaticLib):+ env.append_unique('LIB_' + uselib, i)+ self.msg('Checking for %s' % i, qtStaticLib, 'GREEN')+ else:+ self.msg('Checking for %s' % i, False, 'YELLOW')++ env.append_unique('LIBPATH_' + uselib, qtlibs)+ env.append_unique('INCLUDES_' + uselib, qtincludes)+ env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))+ else:+ # Release library names are like QtCore4+ for k in ("lib%s.a", "lib%s4.a", "%s.lib", "%s4.lib"):+ lib = os.path.join(qtlibs, k % i)+ if os.path.exists(lib):+ env.append_unique('LIB_' + uselib, i + k[k.find("%s") + 2 : k.find('.')])+ self.msg('Checking for %s' % i, lib, 'GREEN')+ break+ else:+ self.msg('Checking for %s' % i, False, 'YELLOW')++ env.append_unique('LIBPATH_' + uselib, qtlibs)+ env.append_unique('INCLUDES_' + uselib, qtincludes)+ env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))++ # Debug library names are like QtCore4d+ uselib = i.upper() + "_debug"+ for k in ("lib%sd.a", "lib%sd4.a", "%sd.lib", "%sd4.lib"):+ lib = os.path.join(qtlibs, k % i)+ if os.path.exists(lib):+ env.append_unique('LIB_' + uselib, i + k[k.find("%s") + 2 : k.find('.')])+ self.msg('Checking for %s' % i, lib, 'GREEN')+ break+ else:+ self.msg('Checking for %s' % i, False, 'YELLOW')++ env.append_unique('LIBPATH_' + uselib, qtlibs)+ env.append_unique('INCLUDES_' + uselib, qtincludes)+ env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i))+ else:+ for i in self.qt4_vars_debug + self.qt4_vars:+ self.check_cfg(package=i, args='--cflags --libs', mandatory=False)++@conf+def simplify_qt4_libs(self):+ # the libpaths make really long command-lines+ # remove the qtcore ones from qtgui, etc+ env = self.env+ def process_lib(vars_, coreval):+ for d in vars_:+ var = d.upper()+ if var == 'QTCORE':+ continue++ value = env['LIBPATH_'+var]+ if value:+ core = env[coreval]+ accu = []+ for lib in value:+ if lib in core:+ continue+ accu.append(lib)+ env['LIBPATH_'+var] = accu++ process_lib(self.qt4_vars, 'LIBPATH_QTCORE')+ process_lib(self.qt4_vars_debug, 'LIBPATH_QTCORE_DEBUG')++@conf+def add_qt4_rpath(self):+ # rpath if wanted+ env = self.env+ if Options.options.want_rpath:+ def process_rpath(vars_, coreval):+ for d in vars_:+ var = d.upper()+ value = env['LIBPATH_'+var]+ if value:+ core = env[coreval]+ accu = []+ for lib in value:+ if var != 'QTCORE':+ if lib in core:+ continue+ accu.append('-Wl,--rpath='+lib)+ env['RPATH_'+var] = accu+ process_rpath(self.qt4_vars, 'LIBPATH_QTCORE')+ process_rpath(self.qt4_vars_debug, 'LIBPATH_QTCORE_DEBUG')++@conf+def set_qt4_libs_to_check(self):+ if not hasattr(self, 'qt4_vars'):+ self.qt4_vars = QT4_LIBS+ self.qt4_vars = Utils.to_list(self.qt4_vars)+ if not hasattr(self, 'qt4_vars_debug'):+ self.qt4_vars_debug = [a + '_debug' for a in self.qt4_vars]+ self.qt4_vars_debug = Utils.to_list(self.qt4_vars_debug)++def options(opt):+ """+ Command-line options+ """+ opt.add_option('--want-rpath', action='store_true', default=False, dest='want_rpath', help='enable the rpath for qt libraries')++ opt.add_option('--header-ext',+ type='string',+ default='',+ help='header extension for moc files',+ dest='qt_header_ext')++ for i in 'qtdir qtbin qtlibs'.split():+ opt.add_option('--'+i, type='string', default='', dest=i)++ opt.add_option('--translate', action="store_true", help="collect translation strings", dest="trans_qt4", default=False)+new file mode 100644@@ -0,0 +1,193 @@+#!/usr/bin/env python+# encoding: utf-8+# daniel.svensson at purplescout.se 2008+# Thomas Nagy 2010 (ita)++"""+Support for Ruby extensions. A C/C++ compiler is required::++ def options(opt):+ opt.load('compiler_c ruby')+ def configure(conf):+ conf.load('compiler_c ruby')+ conf.check_ruby_version((1,8,0))+ conf.check_ruby_ext_devel()+ conf.check_ruby_module('libxml')+ def build(bld):+ bld(+ features = 'c cshlib rubyext',+ source = 'rb_mytest.c',+ target = 'mytest_ext',+ install_path = '${ARCHDIR_RUBY}')+ bld.install_files('${LIBDIR_RUBY}', 'Mytest.rb')+"""++import os+from waflib import Task, Options, Utils+from waflib.TaskGen import before_method, feature, after_method, Task, extension+from waflib.Configure import conf++@feature('rubyext')+@before_method('apply_incpaths', 'apply_lib_vars', 'apply_bundle', 'apply_link')+def init_rubyext(self):+ """+ Add required variables for ruby extensions+ """+ self.install_path = '${ARCHDIR_RUBY}'+ self.uselib = self.to_list(getattr(self, 'uselib', ''))+ if not 'RUBY' in self.uselib:+ self.uselib.append('RUBY')+ if not 'RUBYEXT' in self.uselib:+ self.uselib.append('RUBYEXT')++@feature('rubyext')+@before_method('apply_link', 'propagate_uselib')+def apply_ruby_so_name(self):+ """+ Strip the *lib* prefix from ruby extensions+ """+ self.env['cshlib_PATTERN'] = self.env['cxxshlib_PATTERN'] = self.env['rubyext_PATTERN']++@conf+def check_ruby_version(self, minver=()):+ """+ Checks if ruby is installed.+ If installed the variable RUBY will be set in environment.+ The ruby binary can be overridden by ``--with-ruby-binary`` command-line option.+ """++ if Options.options.rubybinary:+ self.env.RUBY = Options.options.rubybinary+ else:+ self.find_program('ruby', var='RUBY')++ ruby = self.env.RUBY++ try:+ version = self.cmd_and_log([ruby, '-e', 'puts defined?(VERSION) ? VERSION : RUBY_VERSION']).strip()+ except Exception:+ self.fatal('could not determine ruby version')+ self.env.RUBY_VERSION = version++ try:+ ver = tuple(map(int, version.split(".")))+ except Exception:+ self.fatal('unsupported ruby version %r' % version)++ cver = ''+ if minver:+ if ver < minver:+ self.fatal('ruby is too old %r' % ver)+ cver = '.'.join([str(x) for x in minver])+ else:+ cver = ver++ self.msg('Checking for ruby version %s' % str(minver or ''), cver)++@conf+def check_ruby_ext_devel(self):+ """+ Check if a ruby extension can be created+ """+ if not self.env.RUBY:+ self.fatal('ruby detection is required first')++ if not self.env.CC_NAME and not self.env.CXX_NAME:+ self.fatal('load a c/c++ compiler first')++ version = tuple(map(int, self.env.RUBY_VERSION.split(".")))++ def read_out(cmd):+ return Utils.to_list(self.cmd_and_log([self.env.RUBY, '-rrbconfig', '-e', cmd]))++ def read_config(key):+ return read_out('puts Config::CONFIG[%r]' % key)++ ruby = self.env['RUBY']+ archdir = read_config('archdir')+ cpppath = archdir++ if version >= (1, 9, 0):+ ruby_hdrdir = read_config('rubyhdrdir')+ cpppath += ruby_hdrdir+ cpppath += [os.path.join(ruby_hdrdir[0], read_config('arch')[0])]++ self.check(header_name='ruby.h', includes=cpppath, errmsg='could not find ruby header file')++ self.env.LIBPATH_RUBYEXT = read_config('libdir')+ self.env.LIBPATH_RUBYEXT += archdir+ self.env.INCLUDES_RUBYEXT = cpppath+ self.env.CFLAGS_RUBYEXT = read_config('CCDLFLAGS')+ self.env.rubyext_PATTERN = '%s.' + read_config('DLEXT')[0]++ # ok this is really stupid, but the command and flags are combined.+ # so we try to find the first argument...+ flags = read_config('LDSHARED')+ while flags and flags[0][0] != '-':+ flags = flags[1:]++ # we also want to strip out the deprecated ppc flags+ if len(flags) > 1 and flags[1] == "ppc":+ flags = flags[2:]++ self.env.LINKFLAGS_RUBYEXT = flags+ self.env.LINKFLAGS_RUBYEXT += read_config('LIBS')+ self.env.LINKFLAGS_RUBYEXT += read_config('LIBRUBYARG_SHARED')++ if Options.options.rubyarchdir:+ self.env.ARCHDIR_RUBY = Options.options.rubyarchdir+ else:+ self.env.ARCHDIR_RUBY = read_config('sitearchdir')[0]++ if Options.options.rubylibdir:+ self.env.LIBDIR_RUBY = Options.options.rubylibdir+ else:+ self.env.LIBDIR_RUBY = read_config('sitelibdir')[0]++@conf+def check_ruby_module(self, module_name):+ """+ Check if the selected ruby interpreter can require the given ruby module::++ def configure(conf):+ conf.check_ruby_module('libxml')++ :param module_name: module+ :type module_name: string+ """+ self.start_msg('Ruby module %s' % module_name)+ try:+ self.cmd_and_log([self.env['RUBY'], '-e', 'require \'%s\';puts 1' % module_name])+ except Exception:+ self.end_msg(False)+ self.fatal('Could not find the ruby module %r' % module_name)+ self.end_msg(True)++@extension('.rb')+def process(self, node):+ tsk = self.create_task('run_ruby', node)++class run_ruby(Task.Task):+ """+ Task to run ruby files detected by file extension .rb::+ + def options(opt):+ opt.load('ruby')+ + def configure(ctx):+ ctx.check_ruby_version()+ + def build(bld):+ bld.env['RBFLAGS'] = '-e puts "hello world"'+ bld(source='a_ruby_file.rb')+ """+ run_str = '${RUBY} ${RBFLAGS} -I ${SRC[0].parent.abspath()} ${SRC}'++def options(opt):+ """+ Add the ``--with-ruby-archdir``, ``--with-ruby-libdir`` and ``--with-ruby-binary`` options+ """+ opt.add_option('--with-ruby-archdir', type='string', dest='rubyarchdir', help='Specify directory where to install arch specific files')+ opt.add_option('--with-ruby-libdir', type='string', dest='rubylibdir', help='Specify alternate ruby library path')+ opt.add_option('--with-ruby-binary', type='string', dest='rubybinary', help='Specify alternate ruby binary')+new file mode 100644@@ -0,0 +1,77 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)+# Ralf Habacker, 2006 (rh)++import os+from waflib import Utils+from waflib.Tools import ccroot, ar+from waflib.Configure import conf++@conf+def find_scc(conf):+ """+ Detect the Sun C compiler+ """+ v = conf.env+ cc = None+ if v['CC']: cc = v['CC']+ elif 'CC' in conf.environ: cc = conf.environ['CC']+ if not cc: cc = conf.find_program('cc', var='CC')+ if not cc: conf.fatal('Could not find a Sun C compiler')+ cc = conf.cmd_to_list(cc)++ try:+ conf.cmd_and_log(cc + ['-flags'])+ except Exception:+ conf.fatal('%r is not a Sun compiler' % cc)++ v['CC'] = cc+ v['CC_NAME'] = 'sun'++@conf+def scc_common_flags(conf):+ """+ Flags required for executing the sun C compiler+ """+ v = conf.env++ v['CC_SRC_F'] = []+ v['CC_TGT_F'] = ['-c', '-o']++ # linker+ if not v['LINK_CC']: v['LINK_CC'] = v['CC']+ v['CCLNK_SRC_F'] = ''+ v['CCLNK_TGT_F'] = ['-o']+ v['CPPPATH_ST'] = '-I%s'+ v['DEFINES_ST'] = '-D%s'++ v['LIB_ST'] = '-l%s' # template for adding libs+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths+ v['STLIB_ST'] = '-l%s'+ v['STLIBPATH_ST'] = '-L%s'++ v['SONAME_ST'] = '-Wl,-h,%s'+ v['SHLIB_MARKER'] = '-Bdynamic'+ v['STLIB_MARKER'] = '-Bstatic'++ # program+ v['cprogram_PATTERN'] = '%s'++ # shared library+ v['CFLAGS_cshlib'] = ['-Kpic', '-DPIC']+ v['LINKFLAGS_cshlib'] = ['-G']+ v['cshlib_PATTERN'] = 'lib%s.so'++ # static lib+ v['LINKFLAGS_cstlib'] = ['-Bstatic']+ v['cstlib_PATTERN'] = 'lib%s.a'++def configure(conf):+ conf.find_scc()+ conf.find_ar()+ conf.scc_common_flags()+ conf.cc_load_tools()+ conf.cc_add_flags()+ conf.link_add_flags()+new file mode 100644@@ -0,0 +1,78 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)+# Ralf Habacker, 2006 (rh)++import os+from waflib import Utils+from waflib.Tools import ccroot, ar+from waflib.Configure import conf++@conf+def find_sxx(conf):+ """+ Detect the sun C++ compiler+ """+ v = conf.env+ cc = None+ if v['CXX']: cc = v['CXX']+ elif 'CXX' in conf.environ: cc = conf.environ['CXX']+ if not cc: cc = conf.find_program('CC', var='CXX') #studio+ if not cc: cc = conf.find_program('c++', var='CXX')+ if not cc: conf.fatal('Could not find a Sun C++ compiler')+ cc = conf.cmd_to_list(cc)++ try:+ conf.cmd_and_log(cc + ['-flags'])+ except Exception:+ conf.fatal('%r is not a Sun compiler' % cc)++ v['CXX'] = cc+ v['CXX_NAME'] = 'sun'++@conf+def sxx_common_flags(conf):+ """+ Flags required for executing the sun C++ compiler+ """+ v = conf.env++ v['CXX_SRC_F'] = []+ v['CXX_TGT_F'] = ['-c', '-o']++ # linker+ if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX']+ v['CXXLNK_SRC_F'] = []+ v['CXXLNK_TGT_F'] = ['-o']+ v['CPPPATH_ST'] = '-I%s'+ v['DEFINES_ST'] = '-D%s'++ v['LIB_ST'] = '-l%s' # template for adding libs+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths+ v['STLIB_ST'] = '-l%s'+ v['STLIBPATH_ST'] = '-L%s'++ v['SONAME_ST'] = '-Wl,-h,%s'+ v['SHLIB_MARKER'] = '-Bdynamic'+ v['STLIB_MARKER'] = '-Bstatic'++ # program+ v['cxxprogram_PATTERN'] = '%s'++ # shared library+ v['CXXFLAGS_cxxshlib'] = ['-Kpic', '-DPIC']+ v['LINKFLAGS_cxxshlib'] = ['-G']+ v['cxxshlib_PATTERN'] = 'lib%s.so'++ # static lib+ v['LINKFLAGS_cxxstlib'] = ['-Bstatic']+ v['cxxstlib_PATTERN'] = 'lib%s.a'++def configure(conf):+ conf.find_sxx()+ conf.find_ar()+ conf.sxx_common_flags()+ conf.cxx_load_tools()+ conf.cxx_add_flags()+ conf.link_add_flags()+new file mode 100644@@ -0,0 +1,418 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+TeX/LaTeX/PDFLaTeX/XeLaTeX support++Example::++ def configure(conf):+ conf.load('tex')+ if not conf.env.LATEX:+ conf.fatal('The program LaTex is required')++ def build(bld):+ bld(+ features = 'tex',+ type = 'latex', # pdflatex or xelatex+ source = 'document.ltx', # mandatory, the source+ outs = 'ps', # 'pdf' or 'ps pdf'+ deps = 'crossreferencing.lst', # to give dependencies directly+ prompt = 1, # 0 for the batch mode+ )++To configure with a special program use::++ $ PDFLATEX=luatex waf configure+"""++import os, re+from waflib import Utils, Task, Errors, Logs+from waflib.TaskGen import feature, before_method++re_bibunit = re.compile(r'\\(?P<type>putbib)\[(?P<file>[^\[\]]*)\]',re.M)+def bibunitscan(self):+ """+ Parse the inputs and try to find the *bibunit* dependencies++ :return: list of bibunit files+ :rtype: list of :py:class:`waflib.Node.Node`+ """+ node = self.inputs[0]++ nodes = []+ if not node: return nodes++ code = node.read()++ for match in re_bibunit.finditer(code):+ path = match.group('file')+ if path:+ for k in ['', '.bib']:+ # add another loop for the tex include paths?+ Logs.debug('tex: trying %s%s' % (path, k))+ fi = node.parent.find_resource(path + k)+ if fi:+ nodes.append(fi)+ # no break, people are crazy+ else:+ Logs.debug('tex: could not find %s' % path)++ Logs.debug("tex: found the following bibunit files: %s" % nodes)+ return nodes++exts_deps_tex = ['', '.ltx', '.tex', '.bib', '.pdf', '.png', '.eps', '.ps']+"""List of typical file extensions included in latex files"""++exts_tex = ['.ltx', '.tex']+"""List of typical file extensions that contain latex"""++re_tex = re.compile(r'\\(?P<type>include|bibliography|putbib|includegraphics|input|import|bringin|lstinputlisting)(\[[^\[\]]*\])?{(?P<file>[^{}]*)}',re.M)+"""Regexp for expressions that may include latex files"""++g_bibtex_re = re.compile('bibdata', re.M)+"""Regexp for bibtex files"""++class tex(Task.Task):+ """+ Compile a tex/latex file.++ .. inheritance-diagram:: waflib.Tools.tex.latex waflib.Tools.tex.xelatex waflib.Tools.tex.pdflatex+ """++ bibtex_fun, _ = Task.compile_fun('${BIBTEX} ${BIBTEXFLAGS} ${SRCFILE}', shell=False)+ bibtex_fun.__doc__ = """+ Execute the program **bibtex**+ """++ makeindex_fun, _ = Task.compile_fun('${MAKEINDEX} ${MAKEINDEXFLAGS} ${SRCFILE}', shell=False)+ makeindex_fun.__doc__ = """+ Execute the program **makeindex**+ """++ def exec_command(self, cmd, **kw):+ """+ Override :py:meth:`waflib.Task.Task.exec_command` to execute the command without buffering (latex may prompt for inputs)++ :return: the return code+ :rtype: int+ """+ bld = self.generator.bld+ try:+ if not kw.get('cwd', None):+ kw['cwd'] = bld.cwd+ except AttributeError:+ bld.cwd = kw['cwd'] = bld.variant_dir+ return Utils.subprocess.Popen(cmd, **kw).wait()++ def scan_aux(self, node):+ """+ A recursive regex-based scanner that finds included auxiliary files.+ """+ nodes = [node]+ re_aux = re.compile(r'\\@input{(?P<file>[^{}]*)}', re.M)++ def parse_node(node):+ code = node.read()+ for match in re_aux.finditer(code):+ path = match.group('file')+ found = node.parent.find_or_declare(path)+ if found and found not in nodes:+ Logs.debug('tex: found aux node ' + found.abspath())+ nodes.append(found)+ parse_node(found)++ parse_node(node)+ return nodes++ def scan(self):+ """+ A recursive regex-based scanner that finds latex dependencies. It uses :py:attr:`waflib.Tools.tex.re_tex`++ Depending on your needs you might want:++ * to change re_tex::++ from waflib.Tools import tex+ tex.re_tex = myregex++ * or to change the method scan from the latex tasks::++ from waflib.Task import classes+ classes['latex'].scan = myscanfunction+ """+ node = self.inputs[0]++ nodes = []+ names = []+ seen = []+ if not node: return (nodes, names)++ def parse_node(node):+ if node in seen:+ return+ seen.append(node)+ code = node.read()+ global re_tex+ for match in re_tex.finditer(code):+ for path in match.group('file').split(','):+ if path:+ add_name = True+ found = None+ for k in exts_deps_tex:+ Logs.debug('tex: trying %s%s' % (path, k))+ found = node.parent.find_resource(path + k)+ if found and not found in self.outputs:+ nodes.append(found)+ add_name = False+ for ext in exts_tex:+ if found.name.endswith(ext):+ parse_node(found)+ break+ # no break, people are crazy+ if add_name:+ names.append(path)+ parse_node(node)++ for x in nodes:+ x.parent.get_bld().mkdir()++ Logs.debug("tex: found the following : %s and names %s" % (nodes, names))+ return (nodes, names)++ def check_status(self, msg, retcode):+ """+ Check an exit status and raise an error with a particular message++ :param msg: message to display if the code is non-zero+ :type msg: string+ :param retcode: condition+ :type retcode: boolean+ """+ if retcode != 0:+ raise Errors.WafError("%r command exit status %r" % (msg, retcode))++ def bibfile(self):+ """+ Parse the *.aux* files to find a bibfile to process.+ If yes, execute :py:meth:`waflib.Tools.tex.tex.bibtex_fun`+ """+ need_bibtex = False+ try:+ for aux_node in self.aux_nodes:+ ct = aux_node.read()+ if g_bibtex_re.findall(ct):+ need_bibtex = True+ break+ except (OSError, IOError):+ Logs.error('error bibtex scan')+ else:+ # only the main .aux file needs to be processed+ if need_bibtex:+ Logs.warn('calling bibtex')++ self.env.env = {}+ self.env.env.update(os.environ)+ self.env.env.update({'BIBINPUTS': self.TEXINPUTS, 'BSTINPUTS': self.TEXINPUTS})+ self.env.SRCFILE = self.aux_nodes[0].name[:-4]+ self.check_status('error when calling bibtex', self.bibtex_fun())++ def bibunits(self):+ """+ Parse the *.aux* file to find bibunit files. If there are bibunit files,+ execute :py:meth:`waflib.Tools.tex.tex.bibtex_fun`.+ """+ try:+ bibunits = bibunitscan(self)+ except OSError:+ Logs.error('error bibunitscan')+ else:+ if bibunits:+ fn = ['bu' + str(i) for i in xrange(1, len(bibunits) + 1)]+ if fn:+ Logs.warn('calling bibtex on bibunits')++ for f in fn:+ self.env.env = {'BIBINPUTS': self.TEXINPUTS, 'BSTINPUTS': self.TEXINPUTS}+ self.env.SRCFILE = f+ self.check_status('error when calling bibtex', self.bibtex_fun())++ def makeindex(self):+ """+ Look on the filesystem if there is a *.idx* file to process. If yes, execute+ :py:meth:`waflib.Tools.tex.tex.makeindex_fun`+ """+ try:+ idx_path = self.idx_node.abspath()+ os.stat(idx_path)+ except OSError:+ Logs.warn('index file %s absent, not calling makeindex' % idx_path)+ else:+ Logs.warn('calling makeindex')++ self.env.SRCFILE = self.idx_node.name+ self.env.env = {}+ self.check_status('error when calling makeindex %s' % idx_path, self.makeindex_fun())++ def run(self):+ """+ Runs the TeX build process.++ It may require multiple passes, depending on the usage of cross-references,+ bibliographies, content susceptible of needing such passes.+ The appropriate TeX compiler is called until the *.aux* files stop changing.++ Makeindex and bibtex are called if necessary.+ """+ env = self.env++ if not env['PROMPT_LATEX']:+ env.append_value('LATEXFLAGS', '-interaction=batchmode')+ env.append_value('PDFLATEXFLAGS', '-interaction=batchmode')+ env.append_value('XELATEXFLAGS', '-interaction=batchmode')++ fun = self.texfun++ node = self.inputs[0]+ srcfile = node.abspath()++ texinputs = self.env.TEXINPUTS or ''+ self.TEXINPUTS = node.parent.get_bld().abspath() + os.pathsep + node.parent.get_src().abspath() + os.pathsep + texinputs + os.pathsep++ # important, set the cwd for everybody+ self.cwd = self.inputs[0].parent.get_bld().abspath()++ Logs.warn('first pass on %s' % self.__class__.__name__)++ self.env.env = {}+ self.env.env.update(os.environ)+ self.env.env.update({'TEXINPUTS': self.TEXINPUTS})+ self.env.SRCFILE = srcfile+ self.check_status('error when calling latex', fun())++ self.aux_nodes = self.scan_aux(node.change_ext('.aux'))+ self.idx_node = node.change_ext('.idx')++ self.bibfile()+ self.bibunits()+ self.makeindex()++ hash = ''+ for i in range(10):+ # prevent against infinite loops - one never knows++ # watch the contents of file.aux and stop if file.aux does not change anymore+ prev_hash = hash+ try:+ hashes = [Utils.h_file(x.abspath()) for x in self.aux_nodes]+ hash = Utils.h_list(hashes)+ except (OSError, IOError):+ Logs.error('could not read aux.h')+ pass+ if hash and hash == prev_hash:+ break++ # run the command+ Logs.warn('calling %s' % self.__class__.__name__)++ self.env.env = {}+ self.env.env.update(os.environ)+ self.env.env.update({'TEXINPUTS': self.TEXINPUTS})+ self.env.SRCFILE = srcfile+ self.check_status('error when calling %s' % self.__class__.__name__, fun())++class latex(tex):+ texfun, vars = Task.compile_fun('${LATEX} ${LATEXFLAGS} ${SRCFILE}', shell=False)+class pdflatex(tex):+ texfun, vars = Task.compile_fun('${PDFLATEX} ${PDFLATEXFLAGS} ${SRCFILE}', shell=False)+class xelatex(tex):+ texfun, vars = Task.compile_fun('${XELATEX} ${XELATEXFLAGS} ${SRCFILE}', shell=False)++class dvips(Task.Task):+ run_str = '${DVIPS} ${DVIPSFLAGS} ${SRC} -o ${TGT}'+ color = 'BLUE'+ after = ['latex', 'pdflatex', 'xelatex']++class dvipdf(Task.Task):+ run_str = '${DVIPDF} ${DVIPDFFLAGS} ${SRC} ${TGT}'+ color = 'BLUE'+ after = ['latex', 'pdflatex', 'xelatex']++class pdf2ps(Task.Task):+ run_str = '${PDF2PS} ${PDF2PSFLAGS} ${SRC} ${TGT}'+ color = 'BLUE'+ after = ['latex', 'pdflatex', 'xelatex']++@feature('tex')+@before_method('process_source')+def apply_tex(self):+ """+ Create :py:class:`waflib.Tools.tex.tex` objects, and dvips/dvipdf/pdf2ps tasks if necessary (outs='ps', etc).+ """+ if not getattr(self, 'type', None) in ['latex', 'pdflatex', 'xelatex']:+ self.type = 'pdflatex'++ tree = self.bld+ outs = Utils.to_list(getattr(self, 'outs', []))++ # prompt for incomplete files (else the batchmode is used)+ self.env['PROMPT_LATEX'] = getattr(self, 'prompt', 1)++ deps_lst = []++ if getattr(self, 'deps', None):+ deps = self.to_list(self.deps)+ for filename in deps:+ n = self.path.find_resource(filename)+ if not n:+ self.bld.fatal('Could not find %r for %r' % (filename, self))+ if not n in deps_lst:+ deps_lst.append(n)++ for node in self.to_nodes(self.source):++ if self.type == 'latex':+ task = self.create_task('latex', node, node.change_ext('.dvi'))+ elif self.type == 'pdflatex':+ task = self.create_task('pdflatex', node, node.change_ext('.pdf'))+ elif self.type == 'xelatex':+ task = self.create_task('xelatex', node, node.change_ext('.pdf'))++ task.env = self.env++ # add the manual dependencies+ if deps_lst:+ try:+ lst = tree.node_deps[task.uid()]+ for n in deps_lst:+ if not n in lst:+ lst.append(n)+ except KeyError:+ tree.node_deps[task.uid()] = deps_lst++ if self.type == 'latex':+ if 'ps' in outs:+ tsk = self.create_task('dvips', task.outputs, node.change_ext('.ps'))+ tsk.env.env = {'TEXINPUTS' : node.parent.abspath() + os.pathsep + self.path.abspath() + os.pathsep + self.path.get_bld().abspath()}+ if 'pdf' in outs:+ tsk = self.create_task('dvipdf', task.outputs, node.change_ext('.pdf'))+ tsk.env.env = {'TEXINPUTS' : node.parent.abspath() + os.pathsep + self.path.abspath() + os.pathsep + self.path.get_bld().abspath()}+ elif self.type == 'pdflatex':+ if 'ps' in outs:+ self.create_task('pdf2ps', task.outputs, node.change_ext('.ps'))+ self.source = []++def configure(self):+ """+ Try to find the programs tex, latex and others. Do not raise any error if they+ are not found.+ """+ v = self.env+ for p in 'tex latex pdflatex xelatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps'.split():+ try:+ self.find_program(p, var=p.upper())+ except self.errors.ConfigurationError:+ pass+ v['DVIPSFLAGS'] = '-Ppdf'+new file mode 100644@@ -0,0 +1,332 @@+#!/usr/bin/env python+# encoding: utf-8+# Ali Sabil, 2007+# Radosław Szkodziński, 2010++"""+At this point, vala is still unstable, so do not expect+this tool to be too stable either (apis, etc)+"""++import os.path, shutil, re+from waflib import Context, Task, Utils, Logs, Options, Errors+from waflib.TaskGen import extension, taskgen_method+from waflib.Configure import conf++class valac(Task.Task):+ """+ Task to compile vala files.+ """+ #run_str = "${VALAC} ${VALAFLAGS}" # ideally+ #vars = ['VALAC_VERSION']+ vars = ["VALAC", "VALAC_VERSION", "VALAFLAGS"]+ ext_out = ['.h']++ def run(self):+ cmd = [self.env['VALAC']] + self.env['VALAFLAGS']+ cmd.extend([a.abspath() for a in self.inputs])+ ret = self.exec_command(cmd, cwd=self.outputs[0].parent.abspath())++ if ret:+ return ret++ for x in self.outputs:+ if id(x.parent) != id(self.outputs[0].parent):+ shutil.move(self.outputs[0].parent.abspath() + os.sep + x.name, x.abspath())++ if self.generator.dump_deps_node:+ self.generator.dump_deps_node.write('\n'.join(self.generator.packages))++ return ret++valac = Task.update_outputs(valac) # no decorators for python2 classes++@taskgen_method+def init_vala_task(self):+ self.profile = getattr(self, 'profile', 'gobject')++ if self.profile == 'gobject':+ self.uselib = Utils.to_list(getattr(self, 'uselib', []))+ if not 'GOBJECT' in self.uselib:+ self.uselib.append('GOBJECT')++ def addflags(flags):+ self.env.append_value('VALAFLAGS', flags)++ if self.profile:+ addflags('--profile=%s' % self.profile)++ if hasattr(self, 'threading'):+ if self.profile == 'gobject':+ if not 'GTHREAD' in self.uselib:+ self.uselib.append('GTHREAD')+ else:+ #Vala doesn't have threading support for dova nor posix+ Logs.warn("Profile %s means no threading support" % self.profile)+ self.threading = False++ if self.threading:+ addflags('--threading')++ valatask = self.valatask++ self.is_lib = 'cprogram' not in self.features+ if self.is_lib:+ addflags('--library=%s' % self.target)++ h_node = self.path.find_or_declare('%s.h' % self.target)+ valatask.outputs.append(h_node)+ addflags('--header=%s' % h_node.name)++ valatask.outputs.append(self.path.find_or_declare('%s.vapi' % self.target))++ if getattr(self, 'gir', None):+ gir_node = self.path.find_or_declare('%s.gir' % self.gir)+ addflags('--gir=%s' % gir_node.name)+ valatask.outputs.append(gir_node)++ self.vala_target_glib = getattr(self, 'vala_target_glib', getattr(Options.options, 'vala_target_glib', None))+ if self.vala_target_glib:+ addflags('--target-glib=%s' % self.vala_target_glib)++ addflags(['--define=%s' % x for x in getattr(self, 'vala_defines', [])])+++ packages_private = Utils.to_list(getattr(self, 'packages_private', []))+ addflags(['--pkg=%s' % x for x in packages_private])+++ def _get_api_version():+ api_version = '1.0'+ if hasattr(Context.g_module, 'API_VERSION'):+ version = Context.g_module.API_VERSION.split(".")+ if version[0] == "0":+ api_version = "0." + version[1]+ else:+ api_version = version[0] + ".0"+ return api_version++ self.includes = Utils.to_list(getattr(self, 'includes', []))+ self.uselib = self.to_list(getattr(self, 'uselib', []))+ valatask.install_path = getattr(self, 'install_path', '')++ valatask.vapi_path = getattr(self, 'vapi_path', '${DATAROOTDIR}/vala/vapi')+ valatask.pkg_name = getattr(self, 'pkg_name', self.env['PACKAGE'])+ valatask.header_path = getattr(self, 'header_path', '${INCLUDEDIR}/%s-%s' % (valatask.pkg_name, _get_api_version()))+ valatask.install_binding = getattr(self, 'install_binding', True)++ self.packages = packages = Utils.to_list(getattr(self, 'packages', []))+ self.vapi_dirs = vapi_dirs = Utils.to_list(getattr(self, 'vapi_dirs', []))+ includes = []++ if hasattr(self, 'use'):+ local_packages = Utils.to_list(self.use)[:] # make sure to have a copy+ seen = []+ while len(local_packages) > 0:+ package = local_packages.pop()+ if package in seen:+ continue+ seen.append(package)++ # check if the package exists+ try:+ package_obj = self.bld.get_tgen_by_name(package)+ except Errors.WafError:+ continue+ package_name = package_obj.target+ package_node = package_obj.path+ package_dir = package_node.path_from(self.path)++ for task in package_obj.tasks:+ for output in task.outputs:+ if output.name == package_name + ".vapi":+ valatask.set_run_after(task)+ if package_name not in packages:+ packages.append(package_name)+ if package_dir not in vapi_dirs:+ vapi_dirs.append(package_dir)+ if package_dir not in includes:+ includes.append(package_dir)++ if hasattr(package_obj, 'use'):+ lst = self.to_list(package_obj.use)+ lst.reverse()+ local_packages = [pkg for pkg in lst if pkg not in seen] + local_packages++ addflags(['--pkg=%s' % p for p in packages])++ for vapi_dir in vapi_dirs:+ v_node = self.path.find_dir(vapi_dir)+ if not v_node:+ Logs.warn('Unable to locate Vala API directory: %r' % vapi_dir)+ else:+ addflags('--vapidir=%s' % v_node.abspath())+ addflags('--vapidir=%s' % v_node.get_bld().abspath())++ self.dump_deps_node = None+ if self.is_lib and self.packages:+ self.dump_deps_node = self.path.find_or_declare('%s.deps' % self.target)+ valatask.outputs.append(self.dump_deps_node)++ self.includes.append(self.bld.srcnode.abspath())+ self.includes.append(self.bld.bldnode.abspath())+ for include in includes:+ try:+ self.includes.append(self.path.find_dir(include).abspath())+ self.includes.append(self.path.find_dir(include).get_bld().abspath())+ except AttributeError:+ Logs.warn("Unable to locate include directory: '%s'" % include)+++ if self.is_lib and valatask.install_binding:+ headers_list = [o for o in valatask.outputs if o.suffix() == ".h"]+ try:+ self.install_vheader.source = headers_list+ except AttributeError:+ self.install_vheader = self.bld.install_files(valatask.header_path, headers_list, self.env)++ vapi_list = [o for o in valatask.outputs if (o.suffix() in (".vapi", ".deps"))]+ try:+ self.install_vapi.source = vapi_list+ except AttributeError:+ self.install_vapi = self.bld.install_files(valatask.vapi_path, vapi_list, self.env)++ gir_list = [o for o in valatask.outputs if o.suffix() == '.gir']+ try:+ self.install_gir.source = gir_list+ except AttributeError:+ self.install_gir = self.bld.install_files(getattr(self, 'gir_path', '${DATAROOTDIR}/gir-1.0'), gir_list, self.env)++@extension('.vala', '.gs')+def vala_file(self, node):+ """+ Compile a vala file and bind the task to *self.valatask*. If an existing vala task is already set, add the node+ to its inputs. The typical example is::++ def build(bld):+ bld.program(+ packages = 'gtk+-2.0',+ target = 'vala-gtk-example',+ uselib = 'GTK GLIB',+ source = 'vala-gtk-example.vala foo.vala',+ vala_defines = ['DEBUG'] # adds --define=<xyz> values to the command-line++ # the following arguments are for libraries+ #gir = 'hello-1.0',+ #gir_path = '/tmp',+ #vapi_path = '/tmp',+ #pkg_name = 'hello'+ # disable installing of gir, vapi and header+ #install_binding = False++ # profile = 'xyz' # adds --profile=<xyz> to enable profiling+ # threading = True, # add --threading, except if profile is on or not on 'gobject'+ # vala_target_glib = 'xyz' # adds --target-glib=<xyz>, can be given through the command-line option --vala-target-glib=<xyz>+ )+++ :param node: vala file+ :type node: :py:class:`waflib.Node.Node`+ """++ try:+ valatask = self.valatask+ except AttributeError:+ valatask = self.valatask = self.create_task('valac')+ self.init_vala_task()++ valatask.inputs.append(node)+ c_node = node.change_ext('.c')+ valatask.outputs.append(c_node)+ self.source.append(c_node)++@conf+def find_valac(self, valac_name, min_version):+ """+ Find the valac program, and execute it to store the version+ number in *conf.env.VALAC_VERSION*++ :param valac_name: program name+ :type valac_name: string or list of string+ :param min_version: minimum version acceptable+ :type min_version: tuple of int+ """+ valac = self.find_program(valac_name, var='VALAC')+ try:+ output = self.cmd_and_log(valac + ' --version')+ except Exception:+ valac_version = None+ else:+ ver = re.search(r'\d+.\d+.\d+', output).group(0).split('.')+ valac_version = tuple([int(x) for x in ver])++ self.msg('Checking for %s version >= %r' % (valac_name, min_version),+ valac_version, valac_version and valac_version >= min_version)+ if valac and valac_version < min_version:+ self.fatal("%s version %r is too old, need >= %r" % (valac_name, valac_version, min_version))++ self.env['VALAC_VERSION'] = valac_version+ return valac++@conf+def check_vala(self, min_version=(0,8,0), branch=None):+ """+ Check if vala compiler from a given branch exists of at least a given+ version.++ :param min_version: minimum version acceptable (0.8.0)+ :type min_version: tuple+ :param branch: first part of the version number, in case a snapshot is used (0, 8)+ :type branch: tuple of int+ """+ if not branch:+ branch = min_version[:2]+ try:+ find_valac(self, 'valac-%d.%d' % (branch[0], branch[1]), min_version)+ except self.errors.ConfigurationError:+ find_valac(self, 'valac', min_version)++@conf+def check_vala_deps(self):+ """+ Load the gobject and gthread packages if they are missing.+ """+ if not self.env['HAVE_GOBJECT']:+ pkg_args = {'package': 'gobject-2.0',+ 'uselib_store': 'GOBJECT',+ 'args': '--cflags --libs'}+ if getattr(Options.options, 'vala_target_glib', None):+ pkg_args['atleast_version'] = Options.options.vala_target_glib+ self.check_cfg(**pkg_args)++ if not self.env['HAVE_GTHREAD']:+ pkg_args = {'package': 'gthread-2.0',+ 'uselib_store': 'GTHREAD',+ 'args': '--cflags --libs'}+ if getattr(Options.options, 'vala_target_glib', None):+ pkg_args['atleast_version'] = Options.options.vala_target_glib+ self.check_cfg(**pkg_args)++def configure(self):+ """+ Use the following to enforce minimum vala version::++ def configure(conf):+ conf.load('vala', funs='')+ conf.check_vala(min_version=(0,10,0))+ """+ self.load('gnu_dirs')+ self.check_vala_deps()+ self.check_vala()+ self.env.VALAFLAGS = ['-C', '--quiet']++def options(opt):+ """+ Load the :py:mod:`waflib.Tools.gnu_dirs` tool and add the ``--vala-target-glib`` command-line option+ """+ opt.load('gnu_dirs')+ valaopts = opt.add_option_group('Vala Compiler Options')+ valaopts.add_option ('--vala-target-glib', default=None,+ dest='vala_target_glib', metavar='MAJOR.MINOR',+ help='Target version of glib for Vala GObject code generation')+new file mode 100644@@ -0,0 +1,186 @@+#!/usr/bin/env python+# encoding: utf-8+# Carlos Rafael Giani, 2006+# Thomas Nagy, 2010++"""+Unit testing system for C/C++/D providing test execution:++* in parallel, by using ``waf -j``+* partial (only the tests that have changed) or full (by using ``waf --alltests``)++The tests are declared by adding the **test** feature to programs::++ def options(opt):+ opt.load('compiler_cxx waf_unit_test')+ def configure(conf):+ conf.load('compiler_cxx waf_unit_test')+ def build(bld):+ bld(features='cxx cxxprogram test', source='main.cpp', target='app')+ # or+ bld.program(features='test', source='main2.cpp', target='app2')++When the build is executed, the program 'test' will be built and executed without arguments.+The success/failure is detected by looking at the return code. The status and the standard output/error+are stored on the build context.++The results can be displayed by registering a callback function. Here is how to call+the predefined callback::++ def build(bld):+ bld(features='cxx cxxprogram test', source='main.c', target='app')+ from waflib.Tools import waf_unit_test+ bld.add_post_fun(waf_unit_test.summary)+"""++import os, sys+from waflib.TaskGen import feature, after_method+from waflib import Utils, Task, Logs, Options+testlock = Utils.threading.Lock()++@feature('test')+@after_method('apply_link')+def make_test(self):+ """Create the unit test task. There can be only one unit test task by task generator."""+ if getattr(self, 'link_task', None):+ self.create_task('utest', self.link_task.outputs)++class utest(Task.Task):+ """+ Execute a unit test+ """+ color = 'PINK'+ after = ['vnum', 'inst']+ vars = []+ def runnable_status(self):+ """+ Always execute the task if `waf --alltests` was used or no+ tests if ``waf --notests`` was used+ """+ if getattr(Options.options, 'no_tests', False):+ return Task.SKIP_ME++ ret = super(utest, self).runnable_status()+ if ret == Task.SKIP_ME:+ if getattr(Options.options, 'all_tests', False):+ return Task.RUN_ME+ return ret++ def run(self):+ """+ Execute the test. The execution is always successful, but the results+ are stored on ``self.generator.bld.utest_results`` for postprocessing.+ """++ filename = self.inputs[0].abspath()+ self.ut_exec = getattr(self, 'ut_exec', [filename])+ if getattr(self.generator, 'ut_fun', None):+ self.generator.ut_fun(self)++ try:+ fu = getattr(self.generator.bld, 'all_test_paths')+ except AttributeError:+ fu = os.environ.copy()++ lst = []+ for g in self.generator.bld.groups:+ for tg in g:+ if getattr(tg, 'link_task', None):+ lst.append(tg.link_task.outputs[0].parent.abspath())++ def add_path(dct, path, var):+ dct[var] = os.pathsep.join(Utils.to_list(path) + [os.environ.get(var, '')])++ if Utils.is_win32:+ add_path(fu, lst, 'PATH')+ elif Utils.unversioned_sys_platform() == 'darwin':+ add_path(fu, lst, 'DYLD_LIBRARY_PATH')+ add_path(fu, lst, 'LD_LIBRARY_PATH')+ else:+ add_path(fu, lst, 'LD_LIBRARY_PATH')+ self.generator.bld.all_test_paths = fu+++ cwd = getattr(self.generator, 'ut_cwd', '') or self.inputs[0].parent.abspath()++ testcmd = getattr(Options.options, 'testcmd', False)+ if testcmd:+ self.ut_exec = (testcmd % self.ut_exec[0]).split(' ')++ proc = Utils.subprocess.Popen(self.ut_exec, cwd=cwd, env=fu, stderr=Utils.subprocess.PIPE, stdout=Utils.subprocess.PIPE)+ (stdout, stderr) = proc.communicate()++ tup = (filename, proc.returncode, stdout, stderr)+ self.generator.utest_result = tup++ testlock.acquire()+ try:+ bld = self.generator.bld+ Logs.debug("ut: %r", tup)+ try:+ bld.utest_results.append(tup)+ except AttributeError:+ bld.utest_results = [tup]+ finally:+ testlock.release()++def summary(bld):+ """+ Display an execution summary::++ def build(bld):+ bld(features='cxx cxxprogram test', source='main.c', target='app')+ from waflib.Tools import waf_unit_test+ bld.add_post_fun(waf_unit_test.summary)+ """+ lst = getattr(bld, 'utest_results', [])+ if lst:+ Logs.pprint('CYAN', 'execution summary')++ total = len(lst)+ tfail = len([x for x in lst if x[1]])++ Logs.pprint('CYAN', ' tests that pass %d/%d' % (total-tfail, total))+ for (f, code, out, err) in lst:+ if not code:+ Logs.pprint('CYAN', ' %s' % f)++ Logs.pprint('CYAN', ' tests that fail %d/%d' % (tfail, total))+ for (f, code, out, err) in lst:+ if code:+ Logs.pprint('CYAN', ' %s' % f)++def set_exit_code(bld):+ """+ If any of the tests fail waf will exit with that exit code.+ This is useful if you have an automated build system which need+ to report on errors from the tests.+ You may use it like this:++ def build(bld):+ bld(features='cxx cxxprogram test', source='main.c', target='app')+ from waflib.Tools import waf_unit_test+ bld.add_post_fun(waf_unit_test.set_exit_code)+ """+ lst = getattr(bld, 'utest_results', [])+ for (f, code, out, err) in lst:+ if code:+ msg = []+ if out:+ msg.append('stdout:%s%s' % (os.linesep, out.decode('utf-8')))+ if err:+ msg.append('stderr:%s%s' % (os.linesep, err.decode('utf-8')))+ bld.fatal(os.linesep.join(msg))+++def options(opt):+ """+ Provide the ``--alltests``, ``--notests`` and ``--testcmd`` command-line options.+ """+ opt.add_option('--notests', action='store_true', default=False, help='Exec no unit tests', dest='no_tests')+ opt.add_option('--alltests', action='store_true', default=False, help='Exec all unit tests', dest='all_tests')+ opt.add_option('--testcmd', action='store', default=False,+ help = 'Run the unit tests using the test-cmd string'+ ' example "--test-cmd="valgrind --error-exitcode=1'+ ' %s" to run under valgrind', dest='testcmd')+new file mode 100644@@ -0,0 +1,114 @@+#!/usr/bin/env python+# encoding: utf-8+# Brant Young, 2007++"Process *.rc* files for C/C++: X{.rc -> [.res|.rc.o]}"++import re, traceback+from waflib import Task, Logs, Utils+from waflib.TaskGen import extension+from waflib.Tools import c_preproc++@extension('.rc')+def rc_file(self, node):+ """+ Bind the .rc extension to a winrc task+ """+ obj_ext = '.rc.o'+ if self.env['WINRC_TGT_F'] == '/fo':+ obj_ext = '.res'+ rctask = self.create_task('winrc', node, node.change_ext(obj_ext))+ try:+ self.compiled_tasks.append(rctask)+ except AttributeError:+ self.compiled_tasks = [rctask]++re_lines = re.compile(+ '(?:^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*?)\s*$)|'\+ '(?:^\w+[ \t]*(ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)[ \t]*(.*?)\s*$)',+ re.IGNORECASE | re.MULTILINE)++class rc_parser(c_preproc.c_parser):+ def filter_comments(self, filepath):+ code = Utils.readf(filepath)+ if c_preproc.use_trigraphs:+ for (a, b) in c_preproc.trig_def: code = code.split(a).join(b)+ code = c_preproc.re_nl.sub('', code)+ code = c_preproc.re_cpp.sub(c_preproc.repl, code)+ ret = []+ for m in re.finditer(re_lines, code):+ if m.group(2):+ ret.append((m.group(2), m.group(3)))+ else:+ ret.append(('include', m.group(5)))+ return ret++ def addlines(self, node):+ self.currentnode_stack.append(node.parent)+ filepath = node.abspath()++ self.count_files += 1+ if self.count_files > c_preproc.recursion_limit:+ raise c_preproc.PreprocError("recursion limit exceeded")+ pc = self.parse_cache+ Logs.debug('preproc: reading file %r', filepath)+ try:+ lns = pc[filepath]+ except KeyError:+ pass+ else:+ self.lines.extend(lns)+ return++ try:+ lines = self.filter_comments(filepath)+ lines.append((c_preproc.POPFILE, ''))+ lines.reverse()+ pc[filepath] = lines+ self.lines.extend(lines)+ except IOError:+ raise c_preproc.PreprocError("could not read the file %s" % filepath)+ except Exception:+ if Logs.verbose > 0:+ Logs.error("parsing %s failed" % filepath)+ traceback.print_exc()++class winrc(Task.Task):+ """+ Task for compiling resource files+ """+ run_str = '${WINRC} ${WINRCFLAGS} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${WINRC_TGT_F} ${TGT} ${WINRC_SRC_F} ${SRC}'+ color = 'BLUE'++ def scan(self):+ tmp = rc_parser(self.generator.includes_nodes)+ tmp.start(self.inputs[0], self.env)+ nodes = tmp.nodes+ names = tmp.names++ if Logs.verbose:+ Logs.debug('deps: deps for %s: %r; unresolved %r' % (str(self), nodes, names))++ return (nodes, names)++def configure(conf):+ """+ Detect the programs RC or windres, depending on the C/C++ compiler in use+ """+ v = conf.env+ v['WINRC_TGT_F'] = '-o'+ v['WINRC_SRC_F'] = '-i'++ # find rc.exe+ if not conf.env.WINRC:+ if v.CC_NAME == 'msvc':+ conf.find_program('RC', var='WINRC', path_list = v['PATH'])+ v['WINRC_TGT_F'] = '/fo'+ v['WINRC_SRC_F'] = ''+ else:+ conf.find_program('windres', var='WINRC', path_list = v['PATH'])+ if not conf.env.WINRC:+ conf.fatal('winrc was not found!')++ v['WINRCFLAGS'] = []+new file mode 100644@@ -0,0 +1,69 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)+# Ralf Habacker, 2006 (rh)+# Yinon Ehrlich, 2009+# Michael Kuhn, 2009++from waflib.Tools import ccroot, ar+from waflib.Configure import conf++@conf+def find_xlc(conf):+ """+ Detect the Aix C compiler+ """+ cc = conf.find_program(['xlc_r', 'xlc'], var='CC')+ cc = conf.cmd_to_list(cc)+ conf.get_xlc_version(cc)+ conf.env.CC_NAME = 'xlc'+ conf.env.CC = cc++@conf+def xlc_common_flags(conf):+ """+ Flags required for executing the Aix C compiler+ """+ v = conf.env++ v['CC_SRC_F'] = []+ v['CC_TGT_F'] = ['-c', '-o']++ # linker+ if not v['LINK_CC']: v['LINK_CC'] = v['CC']+ v['CCLNK_SRC_F'] = []+ v['CCLNK_TGT_F'] = ['-o']+ v['CPPPATH_ST'] = '-I%s'+ v['DEFINES_ST'] = '-D%s'++ v['LIB_ST'] = '-l%s' # template for adding libs+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths+ v['STLIB_ST'] = '-l%s'+ v['STLIBPATH_ST'] = '-L%s'+ v['RPATH_ST'] = '-Wl,-rpath,%s'++ v['SONAME_ST'] = []+ v['SHLIB_MARKER'] = []+ v['STLIB_MARKER'] = []++ # program+ v['LINKFLAGS_cprogram'] = ['-Wl,-brtl']+ v['cprogram_PATTERN'] = '%s'++ # shared library+ v['CFLAGS_cshlib'] = ['-fPIC']+ v['LINKFLAGS_cshlib'] = ['-G', '-Wl,-brtl,-bexpfull']+ v['cshlib_PATTERN'] = 'lib%s.so'++ # static lib+ v['LINKFLAGS_cstlib'] = []+ v['cstlib_PATTERN'] = 'lib%s.a'++def configure(conf):+ conf.find_xlc()+ conf.find_ar()+ conf.xlc_common_flags()+ conf.cc_load_tools()+ conf.cc_add_flags()+ conf.link_add_flags()+new file mode 100644@@ -0,0 +1,69 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)+# Ralf Habacker, 2006 (rh)+# Yinon Ehrlich, 2009+# Michael Kuhn, 2009++from waflib.Tools import ccroot, ar+from waflib.Configure import conf++@conf+def find_xlcxx(conf):+ """+ Detect the Aix C++ compiler+ """+ cxx = conf.find_program(['xlc++_r', 'xlc++'], var='CXX')+ cxx = conf.cmd_to_list(cxx)+ conf.get_xlc_version(cxx)+ conf.env.CXX_NAME = 'xlc++'+ conf.env.CXX = cxx++@conf+def xlcxx_common_flags(conf):+ """+ Flags required for executing the Aix C++ compiler+ """+ v = conf.env++ v['CXX_SRC_F'] = []+ v['CXX_TGT_F'] = ['-c', '-o']++ # linker+ if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX']+ v['CXXLNK_SRC_F'] = []+ v['CXXLNK_TGT_F'] = ['-o']+ v['CPPPATH_ST'] = '-I%s'+ v['DEFINES_ST'] = '-D%s'++ v['LIB_ST'] = '-l%s' # template for adding libs+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths+ v['STLIB_ST'] = '-l%s'+ v['STLIBPATH_ST'] = '-L%s'+ v['RPATH_ST'] = '-Wl,-rpath,%s'++ v['SONAME_ST'] = []+ v['SHLIB_MARKER'] = []+ v['STLIB_MARKER'] = []++ # program+ v['LINKFLAGS_cxxprogram']= ['-Wl,-brtl']+ v['cxxprogram_PATTERN'] = '%s'++ # shared library+ v['CXXFLAGS_cxxshlib'] = ['-fPIC']+ v['LINKFLAGS_cxxshlib'] = ['-G', '-Wl,-brtl,-bexpfull']+ v['cxxshlib_PATTERN'] = 'lib%s.so'++ # static lib+ v['LINKFLAGS_cxxstlib'] = []+ v['cxxstlib_PATTERN'] = 'lib%s.a'++def configure(conf):+ conf.find_xlcxx()+ conf.find_ar()+ conf.xlcxx_common_flags()+ conf.cxx_load_tools()+ conf.cxx_add_flags()+ conf.link_add_flags()+new file mode 100644@@ -0,0 +1,709 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)++"""+Utilities and platform-specific fixes++The portability fixes try to provide a consistent behavior of the Waf API+through Python versions 2.3 to 3.X and across different platforms (win32, linux, etc)+"""++import os, sys, errno, traceback, inspect, re, shutil, datetime, gc+import subprocess # <- leave this!++try:+ from collections import deque+except ImportError:+ class deque(list):+ """A deque for Python 2.3 which does not have one"""+ def popleft(self):+ return self.pop(0)+try:+ import _winreg as winreg+except ImportError:+ try:+ import winreg+ except ImportError:+ winreg = None++from waflib import Errors++try:+ from collections import UserDict+except ImportError:+ from UserDict import UserDict++try:+ from hashlib import md5+except ImportError:+ try:+ from md5 import md5+ except ImportError:+ # never fail to enable fixes from another module+ pass++try:+ import threading+except ImportError:+ class threading(object):+ """+ A fake threading class for platforms lacking the threading module.+ Use ``waf -j1`` on those platforms+ """+ pass+ class Lock(object):+ """Fake Lock class"""+ def acquire(self):+ pass+ def release(self):+ pass+ threading.Lock = threading.Thread = Lock+else:+ run_old = threading.Thread.run+ def run(*args, **kwargs):+ try:+ run_old(*args, **kwargs)+ except (KeyboardInterrupt, SystemExit):+ raise+ except Exception:+ sys.excepthook(*sys.exc_info())+ threading.Thread.run = run++SIG_NIL = 'iluvcuteoverload'.encode()+"""Arbitrary null value for a md5 hash. This value must be changed when the hash value is replaced (size)"""++O644 = 420+"""Constant representing the permissions for regular files (0644 raises a syntax error on python 3)"""++O755 = 493+"""Constant representing the permissions for executable files (0755 raises a syntax error on python 3)"""++rot_chr = ['\\', '|', '/', '-']+"List of characters to use when displaying the throbber (progress bar)"++rot_idx = 0+"Index of the current throbber character (progress bar)"++try:+ from collections import defaultdict+except ImportError:+ class defaultdict(dict):+ """+ defaultdict was introduced in python 2.5, so we leave it for python 2.4 and 2.3+ """+ def __init__(self, default_factory):+ super(defaultdict, self).__init__()+ self.default_factory = default_factory+ def __getitem__(self, key):+ try:+ return super(defaultdict, self).__getitem__(key)+ except KeyError:+ value = self.default_factory()+ self[key] = value+ return value++is_win32 = sys.platform in ('win32', 'cli')++# we should have put this in the Logs.py file instead :-/+indicator = '\x1b[K%s%s%s\r'+if is_win32 and 'NOCOLOR' in os.environ:+ indicator = '%s%s%s\r'++def readf(fname, m='r', encoding='ISO8859-1'):+ """+ Read an entire file into a string, use this function instead of os.open() whenever possible.++ In practice the wrapper node.read(..) should be preferred to this function::++ def build(ctx):+ from waflib import Utils+ txt = Utils.readf(self.path.find_node('wscript').abspath())+ txt = ctx.path.find_node('wscript').read()++ :type fname: string+ :param fname: Path to file+ :type m: string+ :param m: Open mode+ :type encoding: string+ :param encoding: encoding value, only used for python 3+ :rtype: string+ :return: Content of the file+ """++ if sys.hexversion > 0x3000000 and not 'b' in m:+ m += 'b'+ f = open(fname, m)+ try:+ txt = f.read()+ finally:+ f.close()+ txt = txt.decode(encoding)+ else:+ f = open(fname, m)+ try:+ txt = f.read()+ finally:+ f.close()+ return txt++def writef(fname, data, m='w', encoding='ISO8859-1'):+ """+ Write an entire file from a string, use this function instead of os.open() whenever possible.++ In practice the wrapper node.write(..) should be preferred to this function::++ def build(ctx):+ from waflib import Utils+ txt = Utils.writef(self.path.make_node('i_like_kittens').abspath(), 'some data')+ self.path.make_node('i_like_kittens').write('some data')++ :type fname: string+ :param fname: Path to file+ :type data: string+ :param data: The contents to write to the file+ :type m: string+ :param m: Open mode+ :type encoding: string+ :param encoding: encoding value, only used for python 3+ """+ if sys.hexversion > 0x3000000 and not 'b' in m:+ data = data.encode(encoding)+ m += 'b'+ f = open(fname, m)+ try:+ f.write(data)+ finally:+ f.close()++def h_file(fname):+ """+ Compute a hash value for a file by using md5. This method may be replaced by+ a faster version if necessary. The following uses the file size and the timestamp value::++ import stat+ from waflib import Utils+ def h_file(fname):+ st = os.stat(fname)+ if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')+ m = Utils.md5()+ m.update(str(st.st_mtime))+ m.update(str(st.st_size))+ m.update(fname)+ return m.digest()+ Utils.h_file = h_file++ :type fname: string+ :param fname: path to the file to hash+ :return: hash of the file contents+ """+ f = open(fname, 'rb')+ m = md5()+ try:+ while fname:+ fname = f.read(200000)+ m.update(fname)+ finally:+ f.close()+ return m.digest()++if hasattr(os, 'O_NOINHERIT'):+ def readf_win32(f, m='r', encoding='ISO8859-1'):+ flags = os.O_NOINHERIT | os.O_RDONLY+ if 'b' in m:+ flags |= os.O_BINARY+ if '+' in m:+ flags |= os.O_RDWR+ try:+ fd = os.open(f, flags)+ except OSError:+ raise IOError('Cannot read from %r' % f)++ if sys.hexversion > 0x3000000 and not 'b' in m:+ m += 'b'+ f = open(f, m)+ try:+ txt = f.read()+ finally:+ f.close()+ txt = txt.decode(encoding)+ else:+ f = os.fdopen(fd, m)+ try:+ txt = f.read()+ finally:+ f.close()+ return txt++ def writef_win32(f, data, m='w', encoding='ISO8859-1'):+ if sys.hexversion > 0x3000000 and not 'b' in m:+ data = data.encode(encoding)+ m += 'b'+ flags = os.O_CREAT | os.O_TRUNC | os.O_WRONLY | os.O_NOINHERIT+ if 'b' in m:+ flags |= os.O_BINARY+ if '+' in m:+ flags |= os.O_RDWR+ try:+ fd = os.open(f, flags)+ except OSError:+ raise IOError('Cannot write to %r' % f)+ f = os.fdopen(fd, m)+ try:+ f.write(data)+ finally:+ f.close()++ def h_file_win32(fname):+ try:+ fd = os.open(fname, os.O_BINARY | os.O_RDONLY | os.O_NOINHERIT)+ except OSError:+ raise IOError('Cannot read from %r' % fname)+ f = os.fdopen(fd, 'rb')+ m = md5()+ try:+ while fname:+ fname = f.read(200000)+ m.update(fname)+ finally:+ f.close()+ return m.digest()++ # replace the default functions+ readf_old = readf+ writef_old = writef+ h_file_old = h_file+ readf = readf_win32+ writef = writef_win32+ h_file = h_file_win32++try:+ x = ''.encode('hex')+except LookupError:+ import binascii+ def to_hex(s):+ ret = binascii.hexlify(s)+ if not isinstance(ret, str):+ ret = ret.decode('utf-8')+ return ret+else:+ def to_hex(s):+ return s.encode('hex')++to_hex.__doc__ = """+Return the hexadecimal representation of a string++:param s: string to convert+:type s: string+"""++listdir = os.listdir+if is_win32:+ def listdir_win32(s):+ """+ List the contents of a folder in a portable manner.+ On Win32, return the list of drive letters: ['C:', 'X:', 'Z:']++ :type s: string+ :param s: a string, which can be empty on Windows+ """+ if not s:+ try:+ import ctypes+ except ImportError:+ # there is nothing much we can do+ return [x + ':\\' for x in list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')]+ else:+ dlen = 4 # length of "?:\\x00"+ maxdrives = 26+ buf = ctypes.create_string_buffer(maxdrives * dlen)+ ndrives = ctypes.windll.kernel32.GetLogicalDriveStringsA(maxdrives*dlen, ctypes.byref(buf))+ return [ str(buf.raw[4*i:4*i+2].decode('ascii')) for i in range(int(ndrives/dlen)) ]++ if len(s) == 2 and s[1] == ":":+ s += os.sep++ if not os.path.isdir(s):+ e = OSError('%s is not a directory' % s)+ e.errno = errno.ENOENT+ raise e+ return os.listdir(s)+ listdir = listdir_win32++def num2ver(ver):+ """+ Convert a string, tuple or version number into an integer. The number is supposed to have at most 4 digits::++ from waflib.Utils import num2ver+ num2ver('1.3.2') == num2ver((1,3,2)) == num2ver((1,3,2,0))++ :type ver: string or tuple of numbers+ :param ver: a version number+ """+ if isinstance(ver, str):+ ver = tuple(ver.split('.'))+ if isinstance(ver, tuple):+ ret = 0+ for i in range(4):+ if i < len(ver):+ ret += 256**(3 - i) * int(ver[i])+ return ret+ return ver++def ex_stack():+ """+ Extract the stack to display exceptions++ :return: a string represening the last exception+ """+ exc_type, exc_value, tb = sys.exc_info()+ exc_lines = traceback.format_exception(exc_type, exc_value, tb)+ return ''.join(exc_lines)++def to_list(sth):+ """+ Convert a string argument to a list by splitting on spaces, and pass+ through a list argument unchanged::++ from waflib.Utils import to_list+ lst = to_list("a b c d")++ :param sth: List or a string of items separated by spaces+ :rtype: list+ :return: Argument converted to list++ """+ if isinstance(sth, str):+ return sth.split()+ else:+ return sth++re_nl = re.compile('\r*\n', re.M)+def str_to_dict(txt):+ """+ Parse a string with key = value pairs into a dictionary::++ from waflib import Utils+ x = Utils.str_to_dict('''+ a = 1+ b = test+ ''')++ :type s: string+ :param s: String to parse+ :rtype: dict+ :return: Dictionary containing parsed key-value pairs+ """+ tbl = {}++ lines = re_nl.split(txt)+ for x in lines:+ x = x.strip()+ if not x or x.startswith('#') or x.find('=') < 0:+ continue+ tmp = x.split('=')+ tbl[tmp[0].strip()] = '='.join(tmp[1:]).strip()+ return tbl++def split_path(path):+ return path.split('/')++def split_path_cygwin(path):+ if path.startswith('//'):+ ret = path.split('/')[2:]+ ret[0] = '/' + ret[0]+ return ret+ return path.split('/')++re_sp = re.compile('[/\\\\]')+def split_path_win32(path):+ if path.startswith('\\\\'):+ ret = re.split(re_sp, path)[2:]+ ret[0] = '\\' + ret[0]+ return ret+ return re.split(re_sp, path)++if sys.platform == 'cygwin':+ split_path = split_path_cygwin+elif is_win32:+ split_path = split_path_win32++split_path.__doc__ = """+Split a path by / or \\. This function is not like os.path.split++:type path: string+:param path: path to split+:return: list of strings+"""++def check_dir(path):+ """+ Ensure that a directory exists (similar to ``mkdir -p``).++ :type dir: string+ :param dir: Path to directory+ """+ if not os.path.isdir(path):+ try:+ os.makedirs(path)+ except OSError as e:+ if not os.path.isdir(path):+ raise Errors.WafError('Cannot create the folder %r' % path, ex=e)++def def_attrs(cls, **kw):+ """+ Set default attributes on a class instance++ :type cls: class+ :param cls: the class to update the given attributes in.+ :type kw: dict+ :param kw: dictionary of attributes names and values.+ """+ for k, v in kw.items():+ if not hasattr(cls, k):+ setattr(cls, k, v)++def quote_define_name(s):+ """+ Convert a string to an identifier suitable for C defines.++ :type s: string+ :param s: String to convert+ :rtype: string+ :return: Identifier suitable for C defines+ """+ fu = re.compile("[^a-zA-Z0-9]").sub("_", s)+ fu = fu.upper()+ return fu++def h_list(lst):+ """+ Hash lists. For tuples, using hash(tup) is much more efficient++ :param lst: list to hash+ :type lst: list of strings+ :return: hash of the list+ """+ m = md5()+ m.update(str(lst).encode())+ return m.digest()++def h_fun(fun):+ """+ Hash functions++ :param fun: function to hash+ :type fun: function+ :return: hash of the function+ """+ try:+ return fun.code+ except AttributeError:+ try:+ h = inspect.getsource(fun)+ except IOError:+ h = "nocode"+ try:+ fun.code = h+ except AttributeError:+ pass+ return h++reg_subst = re.compile(r"(\\\\)|(\$\$)|\$\{([^}]+)\}")+def subst_vars(expr, params):+ """+ Replace ${VAR} with the value of VAR taken from a dict or a config set::++ from waflib import Utils+ s = Utils.subst_vars('${PREFIX}/bin', env)++ :type expr: string+ :param expr: String to perform substitution on+ :param params: Dictionary or config set to look up variable values.+ """+ def repl_var(m):+ if m.group(1):+ return '\\'+ if m.group(2):+ return '$'+ try:+ # ConfigSet instances may contain lists+ return params.get_flat(m.group(3))+ except AttributeError:+ return params[m.group(3)]+ return reg_subst.sub(repl_var, expr)++def destos_to_binfmt(key):+ """+ Return the binary format based on the unversioned platform name.++ :param key: platform name+ :type key: string+ :return: string representing the binary format+ """+ if key == 'darwin':+ return 'mac-o'+ elif key in ('win32', 'cygwin', 'uwin', 'msys'):+ return 'pe'+ return 'elf'++def unversioned_sys_platform():+ """+ Return the unversioned platform name.+ Some Python platform names contain versions, that depend on+ the build environment, e.g. linux2, freebsd6, etc.+ This returns the name without the version number. Exceptions are+ os2 and win32, which are returned verbatim.++ :rtype: string+ :return: Unversioned platform name+ """+ s = sys.platform+ if s == 'java':+ # The real OS is hidden under the JVM.+ from java.lang import System+ s = System.getProperty('os.name')+ # see http://lopica.sourceforge.net/os.html for a list of possible values+ if s == 'Mac OS X':+ return 'darwin'+ elif s.startswith('Windows '):+ return 'win32'+ elif s == 'OS/2':+ return 'os2'+ elif s == 'HP-UX':+ return 'hpux'+ elif s in ('SunOS', 'Solaris'):+ return 'sunos'+ else: s = s.lower()+ + # powerpc == darwin for our purposes+ if s == 'powerpc':+ return 'darwin'+ if s == 'win32' or s.endswith('os2') and s != 'sunos2': return s+ return re.split('\d+$', s)[0]++def nada(*k, **kw):+ """+ A function that does nothing++ :return: None+ """+ pass++class Timer(object):+ """+ Simple object for timing the execution of commands.+ Its string representation is the current time::++ from waflib.Utils import Timer+ timer = Timer()+ a_few_operations()+ s = str(timer)+ """+ def __init__(self):+ self.start_time = datetime.datetime.utcnow()++ def __str__(self):+ delta = datetime.datetime.utcnow() - self.start_time+ days = int(delta.days)+ hours = delta.seconds // 3600+ minutes = (delta.seconds - hours * 3600) // 60+ seconds = delta.seconds - hours * 3600 - minutes * 60 + float(delta.microseconds) / 1000 / 1000+ result = ''+ if days:+ result += '%dd' % days+ if days or hours:+ result += '%dh' % hours+ if days or hours or minutes:+ result += '%dm' % minutes+ return '%s%.3fs' % (result, seconds)++if is_win32:+ old = shutil.copy2+ def copy2(src, dst):+ """+ shutil.copy2 does not copy the file attributes on windows, so we+ hack into the shutil module to fix the problem+ """+ old(src, dst)+ shutil.copystat(src, dst)+ setattr(shutil, 'copy2', copy2)++if os.name == 'java':+ # Jython cannot disable the gc but they can enable it ... wtf?+ try:+ gc.disable()+ gc.enable()+ except NotImplementedError:+ gc.disable = gc.enable++def read_la_file(path):+ """+ Read property files, used by msvc.py++ :param path: file to read+ :type path: string+ """+ sp = re.compile(r'^([^=]+)=\'(.*)\'$')+ dc = {}+ for line in readf(path).splitlines():+ try:+ _, left, right, _ = sp.split(line.strip())+ dc[left] = right+ except ValueError:+ pass+ return dc++def nogc(fun):+ """+ Decorator: let a function disable the garbage collector during its execution.+ It is used in the build context when storing/loading the build cache file (pickle)++ :param fun: function to execute+ :type fun: function+ :return: the return value of the function executed+ """+ def f(*k, **kw):+ try:+ gc.disable()+ ret = fun(*k, **kw)+ finally:+ gc.enable()+ return ret+ f.__doc__ = fun.__doc__+ return f++def run_once(fun):+ """+ Decorator: let a function cache its results, use like this::++ @run_once+ def foo(k):+ return 345*2343++ :param fun: function to execute+ :type fun: function+ :return: the return value of the function executed+ """+ cache = {}+ def wrap(k):+ try:+ return cache[k]+ except KeyError:+ ret = fun(k)+ cache[k] = ret+ return ret+ wrap.__cache__ = cache+ return wrap++def get_registry_app_path(key, filename):+ if not winreg:+ return None+ try:+ result = winreg.QueryValue(key, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s.exe" % filename[0])+ except WindowsError:+ pass+ else:+ if os.path.isfile(result):+ return result+new file mode 100644@@ -0,0 +1,3 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)new file mode 100644@@ -0,0 +1,246 @@+import sys, os+try:+ if not (sys.stderr.isatty() and sys.stdout.isatty()):+ raise ValueError('not a tty')++ from ctypes import *++ class COORD(Structure):+ _fields_ = [("X", c_short), ("Y", c_short)]++ class SMALL_RECT(Structure):+ _fields_ = [("Left", c_short), ("Top", c_short), ("Right", c_short), ("Bottom", c_short)]++ class CONSOLE_SCREEN_BUFFER_INFO(Structure):+ _fields_ = [("Size", COORD), ("CursorPosition", COORD), ("Attributes", c_short), ("Window", SMALL_RECT), ("MaximumWindowSize", COORD)]++ class CONSOLE_CURSOR_INFO(Structure):+ _fields_ = [('dwSize',c_ulong), ('bVisible', c_int)]++ sbinfo = CONSOLE_SCREEN_BUFFER_INFO()+ csinfo = CONSOLE_CURSOR_INFO()+ hconsole = windll.kernel32.GetStdHandle(-11)+ windll.kernel32.GetConsoleScreenBufferInfo(hconsole, byref(sbinfo))+ if sbinfo.Size.X < 9 or sbinfo.Size.Y < 9: raise ValueError('small console')+ windll.kernel32.GetConsoleCursorInfo(hconsole, byref(csinfo))+except Exception:+ pass+else:+ import re, threading++ is_vista = getattr(sys, "getwindowsversion", None) and sys.getwindowsversion()[0] >= 6++ try:+ _type = unicode+ except NameError:+ _type = str++ to_int = lambda number, default: number and int(number) or default+ wlock = threading.Lock()++ STD_OUTPUT_HANDLE = -11+ STD_ERROR_HANDLE = -12++ class AnsiTerm(object):+ """+ emulate a vt100 terminal in cmd.exe+ """+ def __init__(self):+ self.encoding = sys.stdout.encoding+ self.hconsole = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)+ self.cursor_history = []+ self.orig_sbinfo = CONSOLE_SCREEN_BUFFER_INFO()+ self.orig_csinfo = CONSOLE_CURSOR_INFO()+ windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(self.orig_sbinfo))+ windll.kernel32.GetConsoleCursorInfo(hconsole, byref(self.orig_csinfo))++ def screen_buffer_info(self):+ sbinfo = CONSOLE_SCREEN_BUFFER_INFO()+ windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(sbinfo))+ return sbinfo++ def clear_line(self, param):+ mode = param and int(param) or 0+ sbinfo = self.screen_buffer_info()+ if mode == 1: # Clear from begining of line to cursor position+ line_start = COORD(0, sbinfo.CursorPosition.Y)+ line_length = sbinfo.Size.X+ elif mode == 2: # Clear entire line+ line_start = COORD(sbinfo.CursorPosition.X, sbinfo.CursorPosition.Y)+ line_length = sbinfo.Size.X - sbinfo.CursorPosition.X+ else: # Clear from cursor position to end of line+ line_start = sbinfo.CursorPosition+ line_length = sbinfo.Size.X - sbinfo.CursorPosition.X+ chars_written = c_int()+ windll.kernel32.FillConsoleOutputCharacterA(self.hconsole, c_wchar(' '), line_length, line_start, byref(chars_written))+ windll.kernel32.FillConsoleOutputAttribute(self.hconsole, sbinfo.Attributes, line_length, line_start, byref(chars_written))++ def clear_screen(self, param):+ mode = to_int(param, 0)+ sbinfo = self.screen_buffer_info()+ if mode == 1: # Clear from begining of screen to cursor position+ clear_start = COORD(0, 0)+ clear_length = sbinfo.CursorPosition.X * sbinfo.CursorPosition.Y+ elif mode == 2: # Clear entire screen and return cursor to home+ clear_start = COORD(0, 0)+ clear_length = sbinfo.Size.X * sbinfo.Size.Y+ windll.kernel32.SetConsoleCursorPosition(self.hconsole, clear_start)+ else: # Clear from cursor position to end of screen+ clear_start = sbinfo.CursorPosition+ clear_length = ((sbinfo.Size.X - sbinfo.CursorPosition.X) + sbinfo.Size.X * (sbinfo.Size.Y - sbinfo.CursorPosition.Y))+ chars_written = c_int()+ windll.kernel32.FillConsoleOutputCharacterA(self.hconsole, c_wchar(' '), clear_length, clear_start, byref(chars_written))+ windll.kernel32.FillConsoleOutputAttribute(self.hconsole, sbinfo.Attributes, clear_length, clear_start, byref(chars_written))++ def push_cursor(self, param):+ sbinfo = self.screen_buffer_info()+ self.cursor_history.append(sbinfo.CursorPosition)++ def pop_cursor(self, param):+ if self.cursor_history:+ old_pos = self.cursor_history.pop()+ windll.kernel32.SetConsoleCursorPosition(self.hconsole, old_pos)++ def set_cursor(self, param):+ y, sep, x = param.partition(';')+ x = to_int(x, 1) - 1+ y = to_int(y, 1) - 1+ sbinfo = self.screen_buffer_info()+ new_pos = COORD(+ min(max(0, x), sbinfo.Size.X),+ min(max(0, y), sbinfo.Size.Y)+ )+ windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos)++ def set_column(self, param):+ x = to_int(param, 1) - 1+ sbinfo = self.screen_buffer_info()+ new_pos = COORD(+ min(max(0, x), sbinfo.Size.X),+ sbinfo.CursorPosition.Y+ )+ windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos)++ def move_cursor(self, x_offset=0, y_offset=0):+ sbinfo = self.screen_buffer_info()+ new_pos = COORD(+ min(max(0, sbinfo.CursorPosition.X + x_offset), sbinfo.Size.X),+ min(max(0, sbinfo.CursorPosition.Y + y_offset), sbinfo.Size.Y)+ )+ windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos)++ def move_up(self, param):+ self.move_cursor(y_offset = -to_int(param, 1))++ def move_down(self, param):+ self.move_cursor(y_offset = to_int(param, 1))++ def move_left(self, param):+ self.move_cursor(x_offset = -to_int(param, 1))++ def move_right(self, param):+ self.move_cursor(x_offset = to_int(param, 1))++ def next_line(self, param):+ sbinfo = self.screen_buffer_info()+ self.move_cursor(+ x_offset = -sbinfo.CursorPosition.X,+ y_offset = to_int(param, 1)+ )++ def prev_line(self, param):+ sbinfo = self.screen_buffer_info()+ self.move_cursor(+ x_offset = -sbinfo.CursorPosition.X,+ y_offset = -to_int(param, 1)+ )++ def rgb2bgr(self, c):+ return ((c&1) << 2) | (c&2) | ((c&4)>>2)++ def set_color(self, param):+ cols = param.split(';')+ sbinfo = CONSOLE_SCREEN_BUFFER_INFO()+ windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(sbinfo))+ attr = sbinfo.Attributes+ for c in cols:+ if is_vista:+ c = int(c)+ else:+ c = to_int(c, 0)+ if c in range(30,38): # fgcolor+ attr = (attr & 0xfff0) | self.rgb2bgr(c-30)+ elif c in range(40,48): # bgcolor+ attr = (attr & 0xff0f) | (self.rgb2bgr(c-40) << 4)+ elif c == 0: # reset+ attr = self.orig_sbinfo.Attributes+ elif c == 1: # strong+ attr |= 0x08+ elif c == 4: # blink not available -> bg intensity+ attr |= 0x80+ elif c == 7: # negative+ attr = (attr & 0xff88) | ((attr & 0x70) >> 4) | ((attr & 0x07) << 4)+ windll.kernel32.SetConsoleTextAttribute(self.hconsole, attr)++ def show_cursor(self,param):+ csinfo.bVisible = 1+ windll.kernel32.SetConsoleCursorInfo(self.hconsole, byref(csinfo))++ def hide_cursor(self,param):+ csinfo.bVisible = 0+ windll.kernel32.SetConsoleCursorInfo(self.hconsole, byref(csinfo))++ ansi_command_table = {+ 'A': move_up,+ 'B': move_down,+ 'C': move_right,+ 'D': move_left,+ 'E': next_line,+ 'F': prev_line,+ 'G': set_column,+ 'H': set_cursor,+ 'f': set_cursor,+ 'J': clear_screen,+ 'K': clear_line,+ 'h': show_cursor,+ 'l': hide_cursor,+ 'm': set_color,+ 's': push_cursor,+ 'u': pop_cursor,+ }+ # Match either the escape sequence or text not containing escape sequence+ ansi_tokens = re.compile('(?:\x1b\[([0-9?;]*)([a-zA-Z])|([^\x1b]+))')+ def write(self, text):+ try:+ wlock.acquire()+ for param, cmd, txt in self.ansi_tokens.findall(text):+ if cmd:+ cmd_func = self.ansi_command_table.get(cmd)+ if cmd_func:+ cmd_func(self, param)+ else:+ self.writeconsole(txt)+ finally:+ wlock.release()++ def writeconsole(self, txt):+ chars_written = c_int()+ writeconsole = windll.kernel32.WriteConsoleA+ if isinstance(txt, _type):+ writeconsole = windll.kernel32.WriteConsoleW++ TINY_STEP = 3000+ for x in range(0, len(txt), TINY_STEP):+ # According MSDN, size should NOT exceed 64 kb (issue #746)+ tiny = txt[x : x + TINY_STEP]+ writeconsole(self.hconsole, tiny, len(tiny), byref(chars_written), None)++ def flush(self):+ pass++ def isatty(self):+ return True++ sys.stderr = sys.stdout = AnsiTerm()+ os.environ['TERM'] = 'vt100'+new file mode 100644@@ -0,0 +1,3 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010 (ita)new file mode 100644@@ -0,0 +1,7 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2011 (ita)++from waflib import Logs+Logs.warn('This tool has been merged to the main library, remove the references to "add_objects"')+new file mode 100644@@ -0,0 +1,161 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+Batched builds - compile faster+instead of compiling object files one by one, c/c++ compilers are often able to compile at once:+cc -c ../file1.c ../file2.c ../file3.c++Files are output on the directory where the compiler is called, and dependencies are more difficult+to track (do not run the command on all source files if only one file changes)++As such, we do as if the files were compiled one by one, but no command is actually run:+replace each cc/cpp Task by a TaskSlave. A new task called TaskMaster collects the+signatures from each slave and finds out the command-line to run.++It is only necessary to import this module in the configuration (no other change required)+"""++import os+from waflib import TaskGen, Task, Build, Logs+from waflib.TaskGen import extension, feature, before_method, after_method++MAX_BATCH = 50++c_str = '${CC} ${CFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} -c ${SRCLST}'+#c_str = '${CC} ${CCFLAGS} ${CPPFLAGS} ${_CCINCFLAGS} ${_CCDEFFLAGS} -c ${SRCLST}'+c_fun, _ = Task.compile_fun_noshell(c_str)++cxx_str = '${CXX} ${CXXFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} -c ${SRCLST}'+#cxx_str = '${CXX} ${CXXFLAGS} ${CPPFLAGS} ${_CXXINCFLAGS} ${_CXXDEFFLAGS} -c ${SRCLST}'+cxx_fun, _ = Task.compile_fun_noshell(cxx_str)++count = 70000+class batch_task(Task.Task):+ color = 'RED'++ after = ['c', 'cxx']+ before = ['cprogram', 'cshlib', 'cstlib', 'cxxprogram', 'cxxshlib', 'cxxstlib']++ def __str__(self):+ return '(batch compilation for %d slaves)\n' % len(self.slaves)++ def __init__(self, *k, **kw):+ Task.Task.__init__(self, *k, **kw)+ self.slaves = []+ self.inputs = []+ self.hasrun = 0++ global count+ count += 1+ self.idx = count++ def add_slave(self, slave):+ self.slaves.append(slave)+ self.set_run_after(slave)++ def runnable_status(self):+ for t in self.run_after:+ if not t.hasrun:+ return Task.ASK_LATER++ for t in self.slaves:+ #if t.executed:+ if t.hasrun != Task.SKIPPED:+ return Task.RUN_ME++ return Task.SKIP_ME++ def run(self):+ outputs = []+ self.outputs = []++ srclst = []+ slaves = []+ for t in self.slaves:+ if t.hasrun != Task.SKIPPED:+ slaves.append(t)+ srclst.append(t.inputs[0].abspath())++ self.env.SRCLST = srclst+ self.cwd = slaves[0].inputs[0].parent.get_bld().abspath()++ if self.slaves[0].__class__.__name__ == 'c':+ ret = c_fun(self)+ else:+ ret = cxx_fun(self)++ if ret:+ return ret++ for t in slaves:+ t.old_post_run()++from waflib.Tools import c, cxx++def hook(name):+ def n_hook(self, node):+ task = self.create_task(name, node, node.change_ext('.o'))+ try:+ self.compiled_tasks.append(task)+ except AttributeError:+ self.compiled_tasks = [task]++ if not getattr(self, 'masters', None):+ self.masters = {}+ self.allmasters = []++ if not node.parent in self.masters:+ m = self.masters[node.parent] = self.master = self.create_task('batch')+ self.allmasters.append(m)+ else:+ m = self.masters[node.parent]+ if len(m.slaves) > MAX_BATCH:+ m = self.masters[node.parent] = self.master = self.create_task('batch')+ self.allmasters.append(m)++ m.add_slave(task)+ return task+ return n_hook++extension('.c')(hook('c'))+extension('.cpp','.cc','.cxx','.C','.c++')(hook('cxx'))++@feature('cprogram', 'cshlib', 'cstaticlib', 'cxxprogram', 'cxxshlib', 'cxxstlib')+@after_method('apply_link')+def link_after_masters(self):+ if getattr(self, 'allmasters', None):+ for m in self.allmasters:+ self.link_task.set_run_after(m)++# Modify the c and cxx task classes - in theory it would be better to+# create subclasses and to re-map the c/c++ extensions+#+for x in ['c', 'cxx']:+ t = Task.classes[x]+ def run(self):+ pass++ def post_run(self):+ #self.executed=1+ pass++ def can_retrieve_cache(self):+ if self.old_can_retrieve_cache():+ for m in self.generator.allmasters:+ try:+ m.slaves.remove(self)+ except ValueError:+ pass #this task wasn't included in that master+ return 1+ else:+ return None++ setattr(t, 'oldrun', t.__dict__['run'])+ setattr(t, 'run', run)+ setattr(t, 'old_post_run', t.post_run)+ setattr(t, 'post_run', post_run)+ setattr(t, 'old_can_retrieve_cache', t.can_retrieve_cache)+ setattr(t, 'can_retrieve_cache', can_retrieve_cache)+new file mode 100644@@ -0,0 +1,58 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2011 (ita)++"""+Latex processing using "biber"+"""++import os+from waflib import Task, Logs++from waflib.Tools import tex as texmodule++class tex(texmodule.tex):+ biber_fun, _ = Task.compile_fun('${BIBER} ${BIBERFLAGS} ${SRCFILE}',shell=False)+ biber_fun.__doc__ = """+ Execute the program **biber**+ """++ def bibfile(self):+ return None++ def bibunits(self):+ self.env.env = {}+ self.env.env.update(os.environ)+ self.env.env.update({'BIBINPUTS': self.TEXINPUTS, 'BSTINPUTS': self.TEXINPUTS})+ self.env.SRCFILE = self.aux_nodes[0].name[:-4]++ if not self.env['PROMPT_LATEX']:+ self.env.append_unique('BIBERFLAGS', '--quiet')++ path = self.aux_nodes[0].abspath()[:-4] + '.bcf'+ if os.path.isfile(path):+ Logs.warn('calling biber')+ self.check_status('error when calling biber, check %s.blg for errors' % (self.env.SRCFILE), self.biber_fun())+ else:+ super(tex, self).bibfile()+ super(tex, self).bibunits()++class latex(tex):+ texfun, vars = Task.compile_fun('${LATEX} ${LATEXFLAGS} ${SRCFILE}', shell=False)+class pdflatex(tex):+ texfun, vars = Task.compile_fun('${PDFLATEX} ${PDFLATEXFLAGS} ${SRCFILE}', shell=False)+class xelatex(tex):+ texfun, vars = Task.compile_fun('${XELATEX} ${XELATEXFLAGS} ${SRCFILE}', shell=False)++def configure(self):+ """+ Almost the same as in tex.py, but try to detect 'biber'+ """+ v = self.env+ for p in ' biber tex latex pdflatex xelatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps'.split():+ try:+ self.find_program(p, var=p.upper())+ except self.errors.ConfigurationError:+ pass+ v['DVIPSFLAGS'] = '-Ppdf'+new file mode 100644@@ -0,0 +1,131 @@+#! /usr/bin/env python+# per rosengren 2011++from os import sep, readlink+from os.path import abspath+from waflib import Logs+from waflib.TaskGen import feature, after_method+from waflib.Task import Task, always_run++def options(opt):+ grp = opt.add_option_group('Bjam Options')+ grp.add_option('--bjam_src', default=None, help='You can find it in <boost root>/tools/jam/src')+ grp.add_option('--bjam_uname', default='linuxx86_64', help='bjam is built in <src>/bin.<uname>/bjam')+ grp.add_option('--bjam_config', default=None)+ grp.add_option('--bjam_toolset', default=None)++def configure(cnf):+ if not cnf.env.BJAM_SRC:+ cnf.env.BJAM_SRC = cnf.options.bjam_src+ if not cnf.env.BJAM_UNAME:+ cnf.env.BJAM_UNAME = cnf.options.bjam_uname+ try:+ cnf.find_program('bjam', path_list=[+ cnf.env.BJAM_SRC + sep + 'bin.' + cnf.env.BJAM_UNAME+ ])+ except Exception as e:+ cnf.env.BJAM = None+ if not cnf.env.BJAM_CONFIG:+ cnf.env.BJAM_CONFIG = cnf.options.bjam_config+ if not cnf.env.BJAM_TOOLSET:+ cnf.env.BJAM_TOOLSET = cnf.options.bjam_toolset++@feature('bjam')+@after_method('process_rule')+def process_bjam(self):+ if not self.bld.env.BJAM:+ self.create_task('bjam_creator')+ self.create_task('bjam_build')+ self.create_task('bjam_installer')+ if getattr(self, 'always', False):+ always_run(bjam_creator)+ always_run(bjam_build)+ always_run(bjam_installer)++class bjam_creator(Task):+ ext_out = 'bjam_exe'+ vars=['BJAM_SRC', 'BJAM_UNAME']+ def run(self):+ env = self.env+ gen = self.generator+ path = gen.path+ bld = gen.bld+ bjam = gen.bld.root.find_dir(env.BJAM_SRC)+ if not bjam:+ Logs.error('Can not find bjam source')+ return -1+ bjam_exe_relpath = 'bin.' + env.BJAM_UNAME + '/bjam'+ bjam_exe = bjam.find_resource(bjam_exe_relpath)+ if bjam_exe:+ env.BJAM = bjam_exe.srcpath()+ return 0+ bjam_cmd = ['./build.sh']+ Logs.debug('runner: ' + bjam.srcpath() + '> ' + str(bjam_cmd))+ result = self.exec_command(bjam_cmd, cwd=bjam.srcpath())+ if not result == 0:+ Logs.error('bjam failed')+ return -1+ bjam_exe = bjam.find_resource(bjam_exe_relpath)+ if bjam_exe:+ env.BJAM = bjam_exe.srcpath()+ return 0+ Logs.error('bjam failed')+ return -1++class bjam_build(Task):+ ext_in = 'bjam_exe'+ ext_out = 'install'+ vars = ['BJAM_TOOLSET']+ def run(self):+ env = self.env+ gen = self.generator+ path = gen.path+ bld = gen.bld+ if hasattr(gen, 'root'):+ build_root = path.find_node(gen.root)+ else:+ build_root = path+ jam = bld.srcnode.find_resource(env.BJAM_CONFIG)+ if jam:+ Logs.debug('bjam: Using jam configuration from ' + jam.srcpath())+ jam_rel = jam.relpath_gen(build_root)+ else:+ Logs.warn('No build configuration in build_config/user-config.jam. Using default')+ jam_rel = None+ bjam_exe = bld.srcnode.find_node(env.BJAM)+ if not bjam_exe:+ Logs.error('env.BJAM is not set')+ return -1+ bjam_exe_rel = bjam_exe.relpath_gen(build_root)+ cmd = ([bjam_exe_rel] ++ (['--user-config=' + jam_rel] if jam_rel else []) ++ ['--stagedir=' + path.get_bld().path_from(build_root)] ++ ['--debug-configuration'] ++ ['--with-' + lib for lib in self.generator.target] ++ (['toolset=' + env.BJAM_TOOLSET] if env.BJAM_TOOLSET else []) ++ ['link=' + 'shared'] ++ ['variant=' + 'release']+ )+ Logs.debug('runner: ' + build_root.srcpath() + '> ' + str(cmd))+ ret = self.exec_command(cmd, cwd=build_root.srcpath())+ if ret != 0:+ return ret+ self.set_outputs(path.get_bld().ant_glob('lib/*') + path.get_bld().ant_glob('bin/*'))+ return 0++class bjam_installer(Task):+ ext_in = 'install'+ def run(self):+ gen = self.generator+ path = gen.path+ for idir, pat in [('${LIBDIR}', 'lib/*'), ('${BINDIR}', 'bin/*')]:+ files = []+ for n in path.get_bld().ant_glob(pat):+ try:+ t = readlink(n.srcpath())+ gen.bld.symlink_as(sep.join([idir, n.name]), t, postpone=False)+ except OSError:+ files.append(n)+ gen.bld.install_files(idir, files, postpone=False)+ return 0+new file mode 100644@@ -0,0 +1,81 @@+#! /usr/bin/env python+# encoding: utf-8+# Yannick LM 2011++"""+Support for the boo programming language, for example::++ bld(features = "boo", # necessary feature+ source = "src.boo", # list of boo files+ gen = "world.dll", # target+ type = "library", # library/exe ("-target:xyz" flag)+ name = "world" # necessary if the target is referenced by 'use'+ )+"""++from waflib import Task+from waflib.Configure import conf+from waflib.TaskGen import feature, after_method, before_method, extension++@extension('.boo')+def boo_hook(self, node):+ # Nothing here yet ...+ # TODO filter the non-boo source files in 'apply_booc' and remove this method+ pass++@feature('boo')+@before_method('process_source')+def apply_booc(self):+ """Create a booc task """+ src_nodes = self.to_nodes(self.source)+ out_node = self.path.find_or_declare(self.gen)++ self.boo_task = self.create_task('booc', src_nodes, [out_node])++ # Set variables used by the 'booc' task+ self.boo_task.env.OUT = '-o:%s' % out_node.abspath()++ # type is "exe" by default+ type = getattr(self, "type", "exe")+ self.boo_task.env.BOO_TARGET_TYPE = "-target:%s" % type++@feature('boo')+@after_method('apply_boo')+def use_boo(self):+ """"+ boo applications honor the **use** keyword::+ """+ dep_names = self.to_list(getattr(self, 'use', []))+ for dep_name in dep_names:+ dep_task_gen = self.bld.get_tgen_by_name(dep_name)+ if not dep_task_gen:+ continue+ dep_task_gen.post()+ dep_task = getattr(dep_task_gen, 'boo_task', None)+ if not dep_task:+ # Try a cs task:+ dep_task = getattr(dep_task_gen, 'cs_task', None)+ if not dep_task:+ # Try a link task:+ dep_task = getattr(dep_task, 'link_task', None)+ if not dep_task:+ # Abort ...+ continue+ self.boo_task.set_run_after(dep_task) # order+ self.boo_task.dep_nodes.extend(dep_task.outputs) # dependency+ self.boo_task.env.append_value('BOO_FLAGS', '-reference:%s' % dep_task.outputs[0].abspath())++class booc(Task.Task):+ """Compiles .boo files """+ color = 'YELLOW'+ run_str = '${BOOC} ${BOO_FLAGS} ${BOO_TARGET_TYPE} ${OUT} ${SRC}'++@conf+def check_booc(self):+ self.find_program('booc', 'BOOC')+ self.env.BOO_FLAGS = ['-nologo']++def configure(self):+ """Check that booc is available """+ self.check_booc()+new file mode 100644@@ -0,0 +1,360 @@+#!/usr/bin/env python+# encoding: utf-8+#+# partially based on boost.py written by Gernot Vormayr+# written by Ruediger Sonderfeld <ruediger@c-plusplus.de>, 2008+# modified by Bjoern Michaelsen, 2008+# modified by Luca Fossati, 2008+# rewritten for waf 1.5.1, Thomas Nagy, 2008+# rewritten for waf 1.6.2, Sylvain Rouquette, 2011++'''++This is an extra tool, not bundled with the default waf binary.+To add the boost tool to the waf file:+$ ./waf-light --tools=compat15,boost+ or, if you have waf >= 1.6.2+$ ./waf update --files=boost++When using this tool, the wscript will look like:++ def options(opt):+ opt.load('compiler_cxx boost')++ def configure(conf):+ conf.load('compiler_cxx boost')+ conf.check_boost(lib='system filesystem')++ def build(bld):+ bld(source='main.cpp', target='app', use='BOOST')++Options are generated, in order to specify the location of boost includes/libraries.+The `check_boost` configuration function allows to specify the used boost libraries.+It can also provide default arguments to the --boost-static and --boost-mt command-line arguments.+Everything will be packaged together in a BOOST component that you can use.++When using MSVC, a lot of compilation flags need to match your BOOST build configuration:+ - you may have to add /EHsc to your CXXFLAGS or define boost::throw_exception if BOOST_NO_EXCEPTIONS is defined.+ Errors: C4530+ - boost libraries will try to be smart and use the (pretty but often not useful) auto-linking feature of MSVC+ So before calling `conf.check_boost` you might want to disabling by adding:+ conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB']+ Errors: + - boost might also be compiled with /MT, which links the runtime statically.+ If you have problems with redefined symbols, + self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']+ self.env['CXXFLAGS_%s' % var] += ['/MD', '/EHsc']+Passing `--boost-linkage_autodetect` might help ensuring having a correct linkage in some basic cases.++'''++import sys+import re+from waflib import Utils, Logs, Errors+from waflib.Configure import conf++BOOST_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib']+BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include']+BOOST_VERSION_FILE = 'boost/version.hpp'+BOOST_VERSION_CODE = '''+#include <iostream>+#include <boost/version.hpp>+int main() { std::cout << BOOST_LIB_VERSION << std::endl; }+'''++# toolsets from {boost_dir}/tools/build/v2/tools/common.jam+PLATFORM = Utils.unversioned_sys_platform()+detect_intel = lambda env: (PLATFORM == 'win32') and 'iw' or 'il'+detect_clang = lambda env: (PLATFORM == 'darwin') and 'clang-darwin' or 'clang'+detect_mingw = lambda env: (re.search('MinGW', env.CXX[0])) and 'mgw' or 'gcc'+BOOST_TOOLSETS = {+ 'borland': 'bcb',+ 'clang': detect_clang,+ 'como': 'como',+ 'cw': 'cw',+ 'darwin': 'xgcc',+ 'edg': 'edg',+ 'g++': detect_mingw,+ 'gcc': detect_mingw,+ 'icpc': detect_intel,+ 'intel': detect_intel,+ 'kcc': 'kcc',+ 'kylix': 'bck',+ 'mipspro': 'mp',+ 'mingw': 'mgw',+ 'msvc': 'vc',+ 'qcc': 'qcc',+ 'sun': 'sw',+ 'sunc++': 'sw',+ 'tru64cxx': 'tru',+ 'vacpp': 'xlc'+}+++def options(opt):+ opt.add_option('--boost-includes', type='string',+ default='', dest='boost_includes',+ help='''path to the boost includes root (~boost root)+ e.g. /path/to/boost_1_47_0''')+ opt.add_option('--boost-libs', type='string',+ default='', dest='boost_libs',+ help='''path to the directory where the boost libs are+ e.g. /path/to/boost_1_47_0/stage/lib''')+ opt.add_option('--boost-static', action='store_true',+ default=False, dest='boost_static',+ help='link with static boost libraries (.lib/.a)')+ opt.add_option('--boost-mt', action='store_true',+ default=False, dest='boost_mt',+ help='select multi-threaded libraries')+ opt.add_option('--boost-abi', type='string', default='', dest='boost_abi',+ help='''select libraries with tags (dgsyp, d for debug),+ see doc Boost, Getting Started, chapter 6.1''')+ opt.add_option('--boost-linkage_autodetect', action="store_true", dest='boost_linkage_autodetect',+ help="auto-detect boost linkage options (don't get used to it / might break other stuff)")+ opt.add_option('--boost-toolset', type='string',+ default='', dest='boost_toolset',+ help='force a toolset e.g. msvc, vc90, \+ gcc, mingw, mgw45 (default: auto)')+ py_version = '%d%d' % (sys.version_info[0], sys.version_info[1])+ opt.add_option('--boost-python', type='string',+ default=py_version, dest='boost_python',+ help='select the lib python with this version \+ (default: %s)' % py_version)+++@conf+def __boost_get_version_file(self, dir):+ try:+ return self.root.find_dir(dir).find_node(BOOST_VERSION_FILE)+ except:+ return None+++@conf+def boost_get_version(self, dir):+ """silently retrieve the boost version number"""+ re_but = re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.*)"$', re.M)+ try:+ val = re_but.search(self.__boost_get_version_file(dir).read()).group(1)+ except:+ val = self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[dir], execute=False, define_ret=True)+ return val+++@conf+def boost_get_includes(self, *k, **kw):+ includes = k and k[0] or kw.get('includes', None)+ if includes and self.__boost_get_version_file(includes):+ return includes+ for dir in BOOST_INCLUDES:+ if self.__boost_get_version_file(dir):+ return dir+ if includes:+ self.fatal('headers not found in %s' % includes)+ else:+ self.fatal('headers not found, please provide a --boost-includes argument (see help)')+++@conf+def boost_get_toolset(self, cc):+ toolset = cc+ if not cc:+ build_platform = Utils.unversioned_sys_platform()+ if build_platform in BOOST_TOOLSETS:+ cc = build_platform+ else:+ cc = self.env.CXX_NAME+ if cc in BOOST_TOOLSETS:+ toolset = BOOST_TOOLSETS[cc]+ return isinstance(toolset, str) and toolset or toolset(self.env)+++@conf+def __boost_get_libs_path(self, *k, **kw):+ ''' return the lib path and all the files in it '''+ if 'files' in kw:+ return self.root.find_dir('.'), Utils.to_list(kw['files'])+ libs = k and k[0] or kw.get('libs', None)+ if libs:+ path = self.root.find_dir(libs)+ files = path.ant_glob('*boost_*')+ if not libs or not files:+ for dir in BOOST_LIBS:+ try:+ path = self.root.find_dir(dir)+ files = path.ant_glob('*boost_*')+ if files:+ break+ path = self.root.find_dir(dir + '64')+ files = path.ant_glob('*boost_*')+ if files:+ break+ except:+ path = None+ if not path:+ if libs:+ self.fatal('libs not found in %s' % libs)+ else:+ self.fatal('libs not found, please provide a --boost-libs argument (see help)')++ self.to_log('Found the boost path in %r with the libraries:' % path)+ for x in files:+ self.to_log(' %r' % x)+ return path, files++@conf+def boost_get_libs(self, *k, **kw):+ '''+ return the lib path and the required libs+ according to the parameters+ '''+ path, files = self.__boost_get_libs_path(**kw)+ t = []+ if kw.get('mt', False):+ t.append('mt')+ if kw.get('abi', None):+ t.append(kw['abi'])+ tags = t and '(-%s)+' % '-'.join(t) or ''+ toolset = self.boost_get_toolset(kw.get('toolset', ''))+ toolset_pat = '(-%s[0-9]{0,3})+' % toolset+ version = '(-%s)+' % self.env.BOOST_VERSION++ def find_lib(re_lib, files):+ for file in files:+ if re_lib.search(file.name):+ self.to_log('Found boost lib %s' % file)+ return file+ return None++ def format_lib_name(name):+ if name.startswith('lib') and self.env.CC_NAME != 'msvc':+ name = name[3:]+ return name[:name.rfind('.')]++ libs = []+ for lib in Utils.to_list(k and k[0] or kw.get('lib', None)):+ py = (lib == 'python') and '(-py%s)+' % kw['python'] or ''+ # Trying libraries, from most strict match to least one+ for pattern in ['boost_%s%s%s%s%s' % (lib, toolset_pat, tags, py, version),+ 'boost_%s%s%s%s' % (lib, tags, py, version),+ 'boost_%s%s%s' % (lib, tags, version),+ # Give up trying to find the right version+ 'boost_%s%s%s%s' % (lib, toolset_pat, tags, py),+ 'boost_%s%s%s' % (lib, tags, py),+ 'boost_%s%s' % (lib, tags)]:+ self.to_log('Trying pattern %s' % pattern)+ file = find_lib(re.compile(pattern), files)+ if file:+ libs.append(format_lib_name(file.name))+ break+ else:+ self.fatal('lib %s not found in %s' % (lib, path.abspath()))++ return path.abspath(), libs+++@conf+def check_boost(self, *k, **kw):+ """+ Initialize boost libraries to be used.++ Keywords: you can pass the same parameters as with the command line (without "--boost-").+ Note that the command line has the priority, and should preferably be used.+ """+ if not self.env['CXX']:+ self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')++ params = {'lib': k and k[0] or kw.get('lib', None)}+ for key, value in self.options.__dict__.items():+ if not key.startswith('boost_'):+ continue+ key = key[len('boost_'):]+ params[key] = value and value or kw.get(key, '')++ var = kw.get('uselib_store', 'BOOST')++ self.start_msg('Checking boost includes')+ self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params)+ self.env.BOOST_VERSION = self.boost_get_version(inc)+ self.end_msg(self.env.BOOST_VERSION)+ if Logs.verbose:+ Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var])++ if not params['lib']:+ return+ self.start_msg('Checking boost libs')+ suffix = params.get('static', None) and 'ST' or ''+ path, libs = self.boost_get_libs(**params)+ self.env['%sLIBPATH_%s' % (suffix, var)] = [path]+ self.env['%sLIB_%s' % (suffix, var)] = libs+ self.end_msg('ok')+ if Logs.verbose:+ Logs.pprint('CYAN', ' path : %s' % path)+ Logs.pprint('CYAN', ' libs : %s' % libs)+++ def try_link():+ if 'system' in params['lib']:+ self.check_cxx(+ fragment="\n".join([+ '#include <boost/system/error_code.hpp>',+ 'int main() { boost::system::error_code c; }',+ ]),+ use=var,+ execute=False,+ )+ if 'thread' in params['lib']:+ self.check_cxx(+ fragment="\n".join([+ '#include <boost/thread.hpp>',+ 'int main() { boost::thread t; }',+ ]),+ use=var,+ execute=False,+ )++ if params.get('linkage_autodetect', False):+ self.start_msg("Attempting to detect boost linkage flags")+ toolset = self.boost_get_toolset(kw.get('toolset', ''))+ if toolset in ['vc']:+ # disable auto-linking feature, causing error LNK1181+ # because the code wants to be linked against+ self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']++ # if no dlls are present, we guess the .lib files are not stubs+ has_dlls = False+ for x in Utils.listdir(path):+ if x.endswith(self.env.cxxshlib_PATTERN % ''):+ has_dlls = True+ break+ if not has_dlls:+ self.env['STLIBPATH_%s' % var] = [path]+ self.env['STLIB_%s' % var] = libs+ del self.env['LIB_%s' % var]+ del self.env['LIBPATH_%s' % var]++ # we attempt to play with some known-to-work CXXFLAGS combinations+ for cxxflags in (['/MD', '/EHsc'], []):+ self.env.stash()+ self.env["CXXFLAGS_%s" % var] += cxxflags+ try:+ try_link()+ self.end_msg("ok: winning cxxflags combination: %s" % (self.env["CXXFLAGS_%s" % var]))+ e = None+ break+ except Errors.ConfigurationError as exc:+ self.env.revert()+ e = exc++ if e is not None:+ self.fatal("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=e)+ else:+ self.fatal("Boost linkage flags auto-detection not implemented (needed ?) for this toolchain")+ else:+ self.start_msg('Checking for boost linkage')+ try:+ try_link()+ except Errors.ConfigurationError as e:+ self.fatal("Could not link against boost libraries using supplied options")+ self.end_msg('ok')+new file mode 100644@@ -0,0 +1,30 @@+#! /usr/bin/env python+# encoding: utf-8+# harald at klimachs.de++import os+from waflib.Tools import ccroot,ar+from waflib.Configure import conf++from waflib.Tools import xlc # method xlc_common_flags+from waflib.Tools.compiler_c import c_compiler+c_compiler['linux'].insert(0, 'c_bgxlc')++@conf+def find_bgxlc(conf):+ cc = conf.find_program(['bgxlc_r','bgxlc'], var='CC')+ cc = conf.cmd_to_list(cc)+ conf.get_xlc_version(cc)+ conf.env.CC = cc+ conf.env.CC_NAME = 'bgxlc'++def configure(conf):+ conf.find_bgxlc()+ conf.find_ar()+ conf.xlc_common_flags()+ conf.env.LINKFLAGS_cshlib = ['-G','-Wl,-bexpfull']+ conf.env.LINKFLAGS_cprogram = []+ conf.cc_load_tools()+ conf.cc_add_flags()+ conf.link_add_flags()+new file mode 100644@@ -0,0 +1,61 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+Dumb C/C++ preprocessor for finding dependencies++It will look at all include files it can find after removing the comments, so the following+will always add the dependency on both "a.h" and "b.h"::++ #include "a.h"+ #ifdef B+ #include "b.h"+ #endif+ int main() {+ return 0;+ }++To use::++ def configure(conf):+ conf.load('compiler_c')+ conf.load('c_dumbpreproc')+"""++import re, sys, os, string, traceback+from waflib import Logs, Build, Utils, Errors+from waflib.Logs import debug, error+from waflib.Tools import c_preproc++re_inc = re.compile(+ '^[ \t]*(#|%:)[ \t]*(include)[ \t]*[<"](.*)[>"]\r*$',+ re.IGNORECASE | re.MULTILINE)++def lines_includes(node):+ code = node.read()+ if c_preproc.use_trigraphs:+ for (a, b) in c_preproc.trig_def: code = code.split(a).join(b)+ code = c_preproc.re_nl.sub('', code)+ code = c_preproc.re_cpp.sub(c_preproc.repl, code)+ return [(m.group(2), m.group(3)) for m in re.finditer(re_inc, code)]++parser = c_preproc.c_parser+class dumb_parser(parser):+ def addlines(self, node):+ if node in self.nodes[:-1]:+ return+ self.currentnode_stack.append(node.parent)+ self.lines = lines_includes(node) + [(c_preproc.POPFILE, '')] + self.lines++ def start(self, node, env):+ self.addlines(node)+ while self.lines:+ (x, y) = self.lines.pop(0)+ if x == c_preproc.POPFILE:+ self.currentnode_stack.pop()+ continue+ self.tryfind(y)++c_preproc.c_parser = dumb_parser+new file mode 100644@@ -0,0 +1,156 @@+#!/usr/bin/env python +# encoding: utf-8 +# Anton Feldmann, 2012 +# "Base for cabal" + +import re +import time +from waflib import TaskGen, Task, Utils +from waflib.Configure import conf +from waflib.Task import always_run +from waflib.TaskGen import extension, feature, after, before, before_method +from waflib.Utils import threading +from shutil import rmtree + +lock = threading.Lock() +registering = False + +def configure(self): + self.find_program('cabal', var='CABAL') + self.find_program('ghc-pkg', var='GHCPKG') + pkgconfd = self.bldnode.abspath() + '/package.conf.d' + self.env.PREFIX = self.bldnode.abspath() + '/dist' + self.env.PKGCONFD = pkgconfd + if self.root.find_node(pkgconfd + '/package.cache'): + self.msg('Using existing package database', pkgconfd, color='CYAN') + else: + pkgdir = self.root.find_dir(pkgconfd) + if pkgdir: + self.msg('Deleting corrupt package database', pkgdir.abspath(), color ='RED') + rmtree(pkgdir.abspath()) + pkgdir = None + + self.cmd_and_log([self.env.GHCPKG, 'init', pkgconfd]) + self.msg('Created package database', pkgconfd, color = 'YELLOW' if pkgdir else 'GREEN') + +@extension('.cabal') +def process_cabal(self, node): + out_dir_node = self.bld.root.find_dir(self.bld.out_dir) + package_node = node.change_ext('.package') + package_node = out_dir_node.find_or_declare(package_node.name) + build_node = node.parent.get_bld() + build_path = build_node.abspath() + config_node = build_node.find_or_declare('setup-config') + inplace_node = build_node.find_or_declare('package.conf.inplace') + + config_task = self.create_task('cabal_configure', node) + config_task.cwd = node.parent.abspath() + config_task.depends_on = getattr(self, 'depends_on', '') + config_task.build_path = build_path + config_task.set_outputs(config_node) + + build_task = self.create_task('cabal_build', config_node) + build_task.cwd = node.parent.abspath() + build_task.build_path = build_path + build_task.set_outputs(inplace_node) + + copy_task = self.create_task('cabal_copy', inplace_node) + copy_task.cwd = node.parent.abspath() + copy_task.depends_on = getattr(self, 'depends_on', '') + copy_task.build_path = build_path + + last_task = copy_task + task_list = [config_task, build_task, copy_task] + + if (getattr(self, 'register', False)): + register_task = self.create_task('cabal_register', inplace_node) + register_task.cwd = node.parent.abspath() + register_task.set_run_after(copy_task) + register_task.build_path = build_path + + pkgreg_task = self.create_task('ghcpkg_register', inplace_node) + pkgreg_task.cwd = node.parent.abspath() + pkgreg_task.set_run_after(register_task) + pkgreg_task.build_path = build_path + + last_task = pkgreg_task + task_list += [register_task, pkgreg_task] + + touch_task = self.create_task('cabal_touch', inplace_node) + touch_task.set_run_after(last_task) + touch_task.set_outputs(package_node) + touch_task.build_path = build_path + + task_list += [touch_task] + + return task_list + +def get_all_src_deps(node): + hs_deps = node.ant_glob('**/*.hs') + hsc_deps = node.ant_glob('**/*.hsc') + lhs_deps = node.ant_glob('**/*.lhs') + c_deps = node.ant_glob('**/*.c') + cpp_deps = node.ant_glob('**/*.cpp') + proto_deps = node.ant_glob('**/*.proto') + return sum([hs_deps, hsc_deps, lhs_deps, c_deps, cpp_deps, proto_deps], []) + +class Cabal(Task.Task): + def scan(self): + return (get_all_src_deps(self.generator.path), ()) + +class cabal_configure(Cabal): + run_str = '${CABAL} configure -v0 --prefix=${PREFIX} --global --user --package-db=${PKGCONFD} --builddir=${tsk.build_path}' + shell = True + + def scan(self): + out_node = self.generator.bld.root.find_dir(self.generator.bld.out_dir) + deps = [out_node.find_or_declare(dep).change_ext('.package') for dep in Utils.to_list(self.depends_on)] + return (deps, ()) + +class cabal_build(Cabal): + run_str = '${CABAL} build -v1 --builddir=${tsk.build_path}/' + shell = True + +class cabal_copy(Cabal): + run_str = '${CABAL} copy -v0 --builddir=${tsk.build_path}' + shell = True + +class cabal_register(Cabal): + run_str = '${CABAL} register -v0 --gen-pkg-config=${tsk.build_path}/pkg.config --builddir=${tsk.build_path}' + shell = True + +class ghcpkg_register(Cabal): + run_str = '${GHCPKG} update -v0 --global --user --package-conf=${PKGCONFD} ${tsk.build_path}/pkg.config' + shell = True + + def runnable_status(self): + global lock, registering + + val = False + lock.acquire() + val = registering + lock.release() + + if val: + return Task.ASK_LATER + + ret = Task.Task.runnable_status(self) + if ret == Task.RUN_ME: + lock.acquire() + registering = True + lock.release() + + return ret + + def post_run(self): + global lock, registering + + lock.acquire() + registering = False + lock.release() + + return Task.Task.post_run(self) + +class cabal_touch(Cabal): + run_str = 'touch ${TGT}' + new file mode 100644@@ -0,0 +1,299 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010 (ita)++"""+This file is provided to enable compatibility with waf 1.5+It was enabled by default in waf 1.6, but it is not used in waf 1.7+"""++import sys+from waflib import ConfigSet, Logs, Options, Scripting, Task, Build, Configure, Node, Runner, TaskGen, Utils, Errors, Context++# the following is to bring some compatibility with waf 1.5 "import waflib.Configure → import Configure"+sys.modules['Environment'] = ConfigSet+ConfigSet.Environment = ConfigSet.ConfigSet++sys.modules['Logs'] = Logs+sys.modules['Options'] = Options+sys.modules['Scripting'] = Scripting+sys.modules['Task'] = Task+sys.modules['Build'] = Build+sys.modules['Configure'] = Configure+sys.modules['Node'] = Node+sys.modules['Runner'] = Runner+sys.modules['TaskGen'] = TaskGen+sys.modules['Utils'] = Utils++from waflib.Tools import c_preproc+sys.modules['preproc'] = c_preproc++from waflib.Tools import c_config+sys.modules['config_c'] = c_config++ConfigSet.ConfigSet.copy = ConfigSet.ConfigSet.derive+ConfigSet.ConfigSet.set_variant = Utils.nada++Build.BuildContext.add_subdirs = Build.BuildContext.recurse+Build.BuildContext.new_task_gen = Build.BuildContext.__call__+Build.BuildContext.is_install = 0+Node.Node.relpath_gen = Node.Node.path_from++def name_to_obj(self, s, env=None):+ Logs.warn('compat: change "name_to_obj(name, env)" by "get_tgen_by_name(name)"')+ return self.get_tgen_by_name(s)+Build.BuildContext.name_to_obj = name_to_obj++def env_of_name(self, name):+ try:+ return self.all_envs[name]+ except KeyError:+ Logs.error('no such environment: '+name)+ return None+Build.BuildContext.env_of_name = env_of_name+++def set_env_name(self, name, env):+ self.all_envs[name] = env+ return env+Configure.ConfigurationContext.set_env_name = set_env_name++def retrieve(self, name, fromenv=None):+ try:+ env = self.all_envs[name]+ except KeyError:+ env = ConfigSet.ConfigSet()+ self.prepare_env(env)+ self.all_envs[name] = env+ else:+ if fromenv: Logs.warn("The environment %s may have been configured already" % name)+ return env+Configure.ConfigurationContext.retrieve = retrieve++Configure.ConfigurationContext.sub_config = Configure.ConfigurationContext.recurse+Configure.ConfigurationContext.check_tool = Configure.ConfigurationContext.load+Configure.conftest = Configure.conf+Configure.ConfigurationError = Errors.ConfigurationError++Options.OptionsContext.sub_options = Options.OptionsContext.recurse+Options.OptionsContext.tool_options = Context.Context.load+Options.Handler = Options.OptionsContext++Task.simple_task_type = Task.task_type_from_func = Task.task_factory+Task.TaskBase.classes = Task.classes++def setitem(self, key, value):+ if key.startswith('CCFLAGS'):+ key = key[1:]+ self.table[key] = value+ConfigSet.ConfigSet.__setitem__ = setitem++@TaskGen.feature('d')+@TaskGen.before('apply_incpaths')+def old_importpaths(self):+ if getattr(self, 'importpaths', []):+ self.includes = self.importpaths++from waflib import Context+eld = Context.load_tool+def load_tool(*k, **kw):+ ret = eld(*k, **kw)+ if 'set_options' in ret.__dict__:+ Logs.warn('compat: rename "set_options" to options')+ ret.options = ret.set_options+ if 'detect' in ret.__dict__:+ Logs.warn('compat: rename "detect" to "configure"')+ ret.configure = ret.detect+ return ret+Context.load_tool = load_tool++rev = Context.load_module+def load_module(path):+ ret = rev(path)+ if 'set_options' in ret.__dict__:+ Logs.warn('compat: rename "set_options" to "options" (%r)' % path)+ ret.options = ret.set_options+ if 'srcdir' in ret.__dict__:+ Logs.warn('compat: rename "srcdir" to "top" (%r)' % path)+ ret.top = ret.srcdir+ if 'blddir' in ret.__dict__:+ Logs.warn('compat: rename "blddir" to "out" (%r)' % path)+ ret.out = ret.blddir+ return ret+Context.load_module = load_module++old_post = TaskGen.task_gen.post+def post(self):+ self.features = self.to_list(self.features)+ if 'cc' in self.features:+ Logs.warn('compat: the feature cc does not exist anymore (use "c")')+ self.features.remove('cc')+ self.features.append('c')+ if 'cstaticlib' in self.features:+ Logs.warn('compat: the feature cstaticlib does not exist anymore (use "cstlib" or "cxxstlib")')+ self.features.remove('cstaticlib')+ self.features.append(('cxx' in self.features) and 'cxxstlib' or 'cstlib')+ if getattr(self, 'ccflags', None):+ Logs.warn('compat: "ccflags" was renamed to "cflags"')+ self.cflags = self.ccflags+ return old_post(self)+TaskGen.task_gen.post = post++def waf_version(*k, **kw):+ Logs.warn('wrong version (waf_version was removed in waf 1.6)')+Utils.waf_version = waf_version+++import os+@TaskGen.feature('c', 'cxx', 'd')+@TaskGen.before('apply_incpaths', 'propagate_uselib_vars')+@TaskGen.after('apply_link', 'process_source')+def apply_uselib_local(self):+ """+ process the uselib_local attribute+ execute after apply_link because of the execution order set on 'link_task'+ """+ env = self.env+ from waflib.Tools.ccroot import stlink_task++ # 1. the case of the libs defined in the project (visit ancestors first)+ # the ancestors external libraries (uselib) will be prepended+ self.uselib = self.to_list(getattr(self, 'uselib', []))+ self.includes = self.to_list(getattr(self, 'includes', []))+ names = self.to_list(getattr(self, 'uselib_local', []))+ get = self.bld.get_tgen_by_name+ seen = set([])+ tmp = Utils.deque(names) # consume a copy of the list of names+ if tmp:+ Logs.warn('compat: "uselib_local" is deprecated, replace by "use"')+ while tmp:+ lib_name = tmp.popleft()+ # visit dependencies only once+ if lib_name in seen:+ continue++ y = get(lib_name)+ y.post()+ seen.add(lib_name)++ # object has ancestors to process (shared libraries): add them to the end of the list+ if getattr(y, 'uselib_local', None):+ for x in self.to_list(getattr(y, 'uselib_local', [])):+ obj = get(x)+ obj.post()+ if getattr(obj, 'link_task', None):+ if not isinstance(obj.link_task, stlink_task):+ tmp.append(x)++ # link task and flags+ if getattr(y, 'link_task', None):++ link_name = y.target[y.target.rfind(os.sep) + 1:]+ if isinstance(y.link_task, stlink_task):+ env.append_value('STLIB', [link_name])+ else:+ # some linkers can link against programs+ env.append_value('LIB', [link_name])++ # the order+ self.link_task.set_run_after(y.link_task)++ # for the recompilation+ self.link_task.dep_nodes += y.link_task.outputs++ # add the link path too+ tmp_path = y.link_task.outputs[0].parent.bldpath()+ if not tmp_path in env['LIBPATH']:+ env.prepend_value('LIBPATH', [tmp_path])++ # add ancestors uselib too - but only propagate those that have no staticlib defined+ for v in self.to_list(getattr(y, 'uselib', [])):+ if not env['STLIB_' + v]:+ if not v in self.uselib:+ self.uselib.insert(0, v)++ # if the library task generator provides 'export_includes', add to the include path+ # the export_includes must be a list of paths relative to the other library+ if getattr(y, 'export_includes', None):+ self.includes.extend(y.to_incnodes(y.export_includes))++@TaskGen.feature('cprogram', 'cxxprogram', 'cstlib', 'cxxstlib', 'cshlib', 'cxxshlib', 'dprogram', 'dstlib', 'dshlib')+@TaskGen.after('apply_link')+def apply_objdeps(self):+ "add the .o files produced by some other object files in the same manner as uselib_local"+ names = getattr(self, 'add_objects', [])+ if not names:+ return+ names = self.to_list(names)++ get = self.bld.get_tgen_by_name+ seen = []+ while names:+ x = names[0]++ # visit dependencies only once+ if x in seen:+ names = names[1:]+ continue++ # object does not exist ?+ y = get(x)++ # object has ancestors to process first ? update the list of names+ if getattr(y, 'add_objects', None):+ added = 0+ lst = y.to_list(y.add_objects)+ lst.reverse()+ for u in lst:+ if u in seen: continue+ added = 1+ names = [u]+names+ if added: continue # list of names modified, loop++ # safe to process the current object+ y.post()+ seen.append(x)++ for t in getattr(y, 'compiled_tasks', []):+ self.link_task.inputs.extend(t.outputs)++@TaskGen.after('apply_link')+def process_obj_files(self):+ if not hasattr(self, 'obj_files'):+ return+ for x in self.obj_files:+ node = self.path.find_resource(x)+ self.link_task.inputs.append(node)++@TaskGen.taskgen_method+def add_obj_file(self, file):+ """Small example on how to link object files as if they were source+ obj = bld.create_obj('cc')+ obj.add_obj_file('foo.o')"""+ if not hasattr(self, 'obj_files'): self.obj_files = []+ if not 'process_obj_files' in self.meths: self.meths.append('process_obj_files')+ self.obj_files.append(file)+++old_define = Configure.ConfigurationContext.__dict__['define']++@Configure.conf+def define(self, key, val, quote=True):+ old_define(self, key, val, quote)+ if key.startswith('HAVE_'):+ self.env[key] = 1++old_undefine = Configure.ConfigurationContext.__dict__['undefine']++@Configure.conf+def undefine(self, key):+ old_undefine(self, key)+ if key.startswith('HAVE_'):+ self.env[key] = 0++# some people might want to use export_incdirs, but it was renamed+def set_incdirs(self, val):+ Logs.warn('compat: change "export_incdirs" by "export_includes"')+ self.export_includes = val+TaskGen.task_gen.export_incdirs = property(None, set_incdirs)+new file mode 100644@@ -0,0 +1,133 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010++import re++import waflib+import waflib.Logs as _msg+from waflib import Task+from waflib.TaskGen import extension, feature, before_method, after_method++cy_api_pat = re.compile(r'\s*?cdef\s*?(public|api)\w*')+re_cyt = re.compile(r"""+ (?:from\s+(\w+)\s+)? # optionally match "from foo" and capture foo+ c?import\s(\w+|[*]) # require "import bar" and capture bar+ """, re.M | re.VERBOSE)++@extension('.pyx')+def add_cython_file(self, node):+ """+ Process a *.pyx* file given in the list of source files. No additional+ feature is required::++ def build(bld):+ bld(features='c cshlib pyext', source='main.c foo.pyx', target='app')+ """+ ext = '.c'+ if 'cxx' in self.features:+ self.env.append_unique('CYTHONFLAGS', '--cplus')+ ext = '.cc'++ for x in getattr(self, 'cython_includes', []):+ # TODO re-use these nodes in "scan" below+ d = self.path.find_dir(x)+ if d:+ self.env.append_unique('CYTHONFLAGS', '-I%s' % d.abspath())++ tsk = self.create_task('cython', node, node.change_ext(ext))+ self.source += tsk.outputs++class cython(Task.Task):+ run_str = '${CYTHON} ${CYTHONFLAGS} -o ${TGT[0].abspath()} ${SRC}'+ color = 'GREEN'++ vars = ['INCLUDES']+ """+ Rebuild whenever the INCLUDES change. The variables such as CYTHONFLAGS will be appended+ by the metaclass.+ """++ ext_out = ['.h']+ """+ The creation of a .h file is known only after the build has begun, so it is not+ possible to compute a build order just by looking at the task inputs/outputs.+ """++ def runnable_status(self):+ """+ Perform a double-check to add the headers created by cython+ to the output nodes. The scanner is executed only when the cython task+ must be executed (optimization).+ """+ ret = super(cython, self).runnable_status()+ if ret == Task.ASK_LATER:+ return ret+ for x in self.generator.bld.raw_deps[self.uid()]:+ if x.startswith('header:'):+ self.outputs.append(self.inputs[0].parent.find_or_declare(x.replace('header:', '')))+ return super(cython, self).runnable_status()++ def scan(self):+ """+ Return the dependent files (.pxd) by looking in the include folders.+ Put the headers to generate in the custom list "bld.raw_deps".+ To inspect the scanne results use::++ $ waf clean build --zones=deps+ """+ txt = self.inputs[0].read()++ mods = []+ for m in re_cyt.finditer(txt):+ if m.group(1): # matches "from foo import bar"+ mods.append(m.group(1))+ else:+ mods.append(m.group(2))++ _msg.debug("cython: mods %r" % mods)+ incs = getattr(self.generator, 'cython_includes', [])+ incs = [self.generator.path.find_dir(x) for x in incs]+ incs.append(self.inputs[0].parent)++ found = []+ missing = []+ for x in mods:+ for y in incs:+ k = y.find_resource(x + '.pxd')+ if k:+ found.append(k)+ break+ else:+ missing.append(x)+ _msg.debug("cython: found %r" % found)++ # Now the .h created - store them in bld.raw_deps for later use+ has_api = False+ has_public = False+ for l in txt.splitlines():+ if cy_api_pat.match(l):+ if ' api ' in l:+ has_api = True+ if ' public ' in l:+ has_public = True+ name = self.inputs[0].name.replace('.pyx', '')+ if has_api:+ missing.append('header:%s_api.h' % name)+ if has_public:+ missing.append('header:%s.h' % name)++ return (found, missing)++def options(ctx):+ ctx.add_option('--cython-flags', action='store', default='', help='space separated list of flags to pass to cython')++def configure(ctx):+ if not ctx.env.CC and not ctx.env.CXX:+ ctx.fatal('Load a C/C++ compiler first')+ if not ctx.env.PYTHON:+ ctx.fatal('Load the python tool first!')+ ctx.find_program('cython', var='CYTHON')+ if ctx.options.cython_flags:+ ctx.env.CYTHONFLAGS = ctx.options.cython_flags+new file mode 100644@@ -0,0 +1,79 @@+#!/usr/bin/env python+# encoding: utf-8+# Jérôme Carretero, 2011 (zougloub)++from waflib import Configure, Options, Utils+from waflib.Tools import ccroot+from waflib.Configure import conf++@conf+def find_dcc(conf):+ cc = conf.find_program(['dcc'], var='CC', path_list=getattr(Options.options, 'diabbindir', ""))+ cc = conf.cmd_to_list(cc)+ conf.env.CC_NAME = 'dcc'+ conf.env.CC = cc++@conf+def find_dld(conf):+ ld = conf.find_program(['dld'], var='LINK_CC', path_list=getattr(Options.options, 'diabbindir', ""))+ ld = conf.cmd_to_list(ld)+ conf.env.LINK_CC_NAME = 'dld'+ conf.env.LINK_CC = ld++@conf+def find_dar(conf):+ ar = conf.find_program(['dar'], var='DAR', path_list=getattr(Options.options, 'diabbindir', ""))+ ar = conf.cmd_to_list(ar)+ conf.env.AR = ar+ conf.env.AR_NAME = 'dar'+ conf.env.ARFLAGS = 'rcs'++@conf+def find_ddump(conf):+ prg = conf.find_program(['ddump'], var='DDUMP', path_list=getattr(Options.options, 'diabbindir', ""))+ prg = conf.cmd_to_list(prg)+ conf.env.DDUMP = prg++@conf+def dcc_common_flags(conf):+ v = conf.env+ v['CC_SRC_F'] = []+ v['CC_TGT_F'] = ['-c', '-o']++ # linker+ if not v['LINK_CC']: v['LINK_CC'] = v['CC']+ v['CCLNK_SRC_F'] = []+ v['CCLNK_TGT_F'] = ['-o']+ v['CPPPATH_ST'] = '-I%s'+ v['DEFINES_ST'] = '-D%s'++ v['LIB_ST'] = '-l:%s' # template for adding libs+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths+ v['STLIB_ST'] = '-l:%s'+ v['STLIBPATH_ST'] = '-L%s'+ v['RPATH_ST'] = '-Wl,-rpath,%s'+ #v['STLIB_MARKER'] = '-Wl,-Bstatic'++ # program+ v['cprogram_PATTERN'] = '%s.elf'++ # static lib+ v['LINKFLAGS_cstlib'] = ['-Wl,-Bstatic']+ v['cstlib_PATTERN'] = 'lib%s.a'++def configure(conf):+ conf.find_dcc()+ conf.find_dar()+ conf.find_dld()+ conf.find_ddump()+ conf.dcc_common_flags()+ conf.cc_load_tools()+ conf.cc_add_flags()+ conf.link_add_flags()++def options(opt):+ """+ Add the ``--with-diab-bindir`` command-line options.+ """+ opt.add_option('--with-diab-bindir', type='string', dest='diabbindir', help = 'Specify alternate diab bin folder', default="")+new file mode 100644@@ -0,0 +1,164 @@+#! /usr/bin/env python+# encoding: UTF-8+# Thomas Nagy 2008-2010 (ita)++"""++Doxygen support++Variables passed to bld():+* doxyfile -- the Doxyfile to use++ported from waf 1.5 (incomplete)+"""++from fnmatch import fnmatchcase+import os, os.path, re, stat+from waflib import Task, Utils, Node, Logs+from waflib.TaskGen import feature++DOXY_STR = '${DOXYGEN} - '+DOXY_FMTS = 'html latex man rft xml'.split()+DOXY_FILE_PATTERNS = '*.' + ' *.'.join('''+c cc cxx cpp c++ java ii ixx ipp i++ inl h hh hxx hpp h++ idl odl cs php php3+inc m mm py f90c cc cxx cpp c++ java ii ixx ipp i++ inl h hh hxx+'''.split())++re_nl = re.compile('\\\\\r*\n', re.MULTILINE)++class doxygen(Task.Task):+ vars = ['DOXYGEN', 'DOXYFLAGS']+ color = 'BLUE'++ def runnable_status(self):+ '''+ self.pars are populated in runnable_status - because this function is being+ run *before* both self.pars "consumers" - scan() and run()++ set output_dir (node) for the output+ '''++ for x in self.run_after:+ if not x.hasrun:+ return Task.ASK_LATER++ if not getattr(self, 'pars', None):+ txt = self.inputs[0].read()+ txt = re_nl.sub('', txt)+ self.pars = Utils.str_to_dict(txt)+ if not self.pars.get('OUTPUT_DIRECTORY'):+ self.pars['OUTPUT_DIRECTORY'] = self.inputs[0].parent.get_bld().abspath()+ if not self.pars.get('INPUT'):+ self.pars['INPUT'] = self.inputs[0].parent.abspath()++ if not getattr(self, 'output_dir', None):+ bld = self.generator.bld+ # First try to find an absolute path, then find or declare a relative path+ self.output_dir = bld.root.find_dir(self.pars['OUTPUT_DIRECTORY'])+ if not self.output_dir:+ self.output_dir = bld.path.find_or_declare(self.pars['OUTPUT_DIRECTORY'])+++ self.signature()+ return Task.Task.runnable_status(self)++ def scan(self):+ if self.pars.get('RECURSIVE') == 'YES':+ Logs.warn("Doxygen RECURSIVE dependencies are not supported")++ inputs = self.pars.get('INPUT').split()+ exclude_patterns = self.pars.get('EXCLUDE_PATTERNS', '').split()+ file_patterns = self.pars.get('FILE_PATTERNS', '').split()+ if not file_patterns:+ file_patterns = DOXY_FILE_PATTERNS++ nodes = []+ names = []+ for i in inputs:+ node = self.generator.bld.root.make_node(i)+ if node:+ if os.path.isdir(node.abspath()):+ for m in node.ant_glob(file_patterns):+ nodes.append(self.generator.bld.root.make_node(m.abspath()))+ else:+ nodes.append(node)+ else:+ names.append(i)++ return (nodes, names)++ def run(self):+ code = '\n'.join(['%s = %s' % (x, self.pars[x]) for x in self.pars])+ code = code.encode() # for python 3+ #fmt = DOXY_STR % (self.inputs[0].parent.abspath())+ cmd = Utils.subst_vars(DOXY_STR, self.env)+ env = self.env.env or None+ proc = Utils.subprocess.Popen(cmd, shell=True, stdin=Utils.subprocess.PIPE, env=env, cwd=self.generator.bld.path.get_bld().abspath())+ proc.communicate(code)+ return proc.returncode++ def post_run(self):+ nodes = self.output_dir.ant_glob('**/*')+ for x in nodes:+ x.sig = Utils.h_file(x.abspath())+ self.outputs += nodes+ return Task.Task.post_run(self)++ #def install(self):+ # if getattr(self.generator, 'install_to', None):+ # update_build_dir(self.inputs[0].parent, self.env)+ # pattern = getattr(self, 'instype', 'html/*')+ # self.generator.bld.install_files(self.generator.install_to, self.generator.path.ant_glob(pattern, dir=0, src=0))++class tar(Task.Task):+ "quick tar creation"+ run_str = '${TAR} ${TAROPTS} ${TGT} ${SRC}'+ color = 'RED'+ after = ['doxygen']+ def runnable_status(self):+ for x in getattr(self, 'input_tasks', []):+ if not x.hasrun:+ return Task.ASK_LATER++ if not getattr(self, 'tar_done_adding', None):+ # execute this only once+ self.tar_done_adding = True+ for x in getattr(self, 'input_tasks', []):+ self.set_inputs(x.outputs)+ if not self.inputs:+ return Task.SKIP_ME+ return Task.Task.runnable_status(self)++ def __str__(self):+ tgt_str = ' '.join([a.nice_path(self.env) for a in self.outputs])+ return '%s: %s\n' % (self.__class__.__name__, tgt_str)++@feature('doxygen')+def process_doxy(self):+ if not getattr(self, 'doxyfile', None):+ self.generator.bld.fatal('no doxyfile??')++ node = self.doxyfile+ if not isinstance(node, Node.Node):+ node = self.path.find_resource(node)+ if not node:+ raise ValueError('doxygen file not found')++ # the task instance+ dsk = self.create_task('doxygen', node)++ if getattr(self, 'doxy_tar', None):+ tsk = self.create_task('tar')+ tsk.input_tasks = [dsk]+ tsk.set_outputs(self.path.find_or_declare(self.doxy_tar))+ if self.doxy_tar.endswith('bz2'):+ tsk.env['TAROPTS'] = ['cjf']+ elif self.doxy_tar.endswith('gz'):+ tsk.env['TAROPTS'] = ['czf']+ else:+ tsk.env['TAROPTS'] = ['cf']++def configure(conf):+ conf.find_program('doxygen', var='DOXYGEN')+ conf.find_program('tar', var='TAR')+new file mode 100644@@ -0,0 +1,87 @@+#! /usr/bin/env python+# encoding: utf-8+# Matt Clarkson, 2012++'''+DPAPI access library (http://msdn.microsoft.com/en-us/library/ms995355.aspx)+This file uses code originally created by Crusher Joe:+http://article.gmane.org/gmane.comp.python.ctypes/420+And modified by Wayne Koorts:+http://stackoverflow.com/questions/463832/using-dpapi-with-python+'''++from ctypes import windll, byref, cdll, Structure, POINTER, c_char, c_buffer+from ctypes.wintypes import DWORD+from waflib.Configure import conf++LocalFree = windll.kernel32.LocalFree+memcpy = cdll.msvcrt.memcpy+CryptProtectData = windll.crypt32.CryptProtectData+CryptUnprotectData = windll.crypt32.CryptUnprotectData+CRYPTPROTECT_UI_FORBIDDEN = 0x01+try:+ extra_entropy = 'cl;ad13 \0al;323kjd #(adl;k$#ajsd'.encode('ascii')+except AttributeError:+ extra_entropy = 'cl;ad13 \0al;323kjd #(adl;k$#ajsd'++class DATA_BLOB(Structure):+ _fields_ = [+ ('cbData', DWORD),+ ('pbData', POINTER(c_char))+ ]++def get_data(blob_out):+ cbData = int(blob_out.cbData)+ pbData = blob_out.pbData+ buffer = c_buffer(cbData)+ memcpy(buffer, pbData, cbData)+ LocalFree(pbData);+ return buffer.raw++@conf+def dpapi_encrypt_data(self, input_bytes, entropy = extra_entropy):+ '''+ Encrypts data and returns byte string++ :param input_bytes: The data to be encrypted+ :type input_bytes: String or Bytes+ :param entropy: Extra entropy to add to the encryption process (optional)+ :type entropy: String or Bytes+ '''+ if not isinstance(input_bytes, bytes) or not isinstance(entropy, bytes):+ self.fatal('The inputs to dpapi must be bytes')+ buffer_in = c_buffer(input_bytes, len(input_bytes))+ buffer_entropy = c_buffer(entropy, len(entropy))+ blob_in = DATA_BLOB(len(input_bytes), buffer_in)+ blob_entropy = DATA_BLOB(len(entropy), buffer_entropy)+ blob_out = DATA_BLOB()++ if CryptProtectData(byref(blob_in), 'python_data', byref(blob_entropy), + None, None, CRYPTPROTECT_UI_FORBIDDEN, byref(blob_out)):+ return get_data(blob_out)+ else:+ self.fatal('Failed to decrypt data')++@conf+def dpapi_decrypt_data(self, encrypted_bytes, entropy = extra_entropy):+ '''+ Decrypts data and returns byte string++ :param encrypted_bytes: The encrypted data+ :type encrypted_bytes: Bytes+ :param entropy: Extra entropy to add to the encryption process (optional)+ :type entropy: String or Bytes+ '''+ if not isinstance(encrypted_bytes, bytes) or not isinstance(entropy, bytes):+ self.fatal('The inputs to dpapi must be bytes')+ buffer_in = c_buffer(encrypted_bytes, len(encrypted_bytes))+ buffer_entropy = c_buffer(entropy, len(entropy))+ blob_in = DATA_BLOB(len(encrypted_bytes), buffer_in)+ blob_entropy = DATA_BLOB(len(entropy), buffer_entropy)+ blob_out = DATA_BLOB()+ if CryptUnprotectData(byref(blob_in), None, byref(blob_entropy), None,+ None, CRYPTPROTECT_UI_FORBIDDEN, byref(blob_out)):+ return get_data(blob_out)+ else:+ self.fatal('Failed to decrypt data')+new file mode 100644@@ -0,0 +1,61 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+Dumb C/C++ preprocessor for finding dependencies++It will look at all include files it can find after removing the comments, so the following+will always add the dependency on both "a.h" and "b.h"::++ #include "a.h"+ #ifdef B+ #include "b.h"+ #endif+ int main() {+ return 0;+ }++To use::++ def configure(conf):+ conf.load('compiler_c')+ conf.load('c_dumbpreproc')+"""++import re, sys, os, string, traceback+from waflib import Logs, Build, Utils, Errors+from waflib.Logs import debug, error+from waflib.Tools import c_preproc++re_inc = re.compile(+ '^[ \t]*(#|%:)[ \t]*(include)[ \t]*[<"](.*)[>"]\r*$',+ re.IGNORECASE | re.MULTILINE)++def lines_includes(node):+ code = node.read()+ if c_preproc.use_trigraphs:+ for (a, b) in c_preproc.trig_def: code = code.split(a).join(b)+ code = c_preproc.re_nl.sub('', code)+ code = c_preproc.re_cpp.sub(c_preproc.repl, code)+ return [(m.group(2), m.group(3)) for m in re.finditer(re_inc, code)]++parser = c_preproc.c_parser+class dumb_parser(parser):+ def addlines(self, node):+ if node in self.nodes[:-1]:+ return+ self.currentnode_stack.append(node.parent)+ self.lines = lines_includes(node) + [(c_preproc.POPFILE, '')] + self.lines++ def start(self, node, env):+ self.addlines(node)+ while self.lines:+ (x, y) = self.lines.pop(0)+ if x == c_preproc.POPFILE:+ self.currentnode_stack.pop()+ continue+ self.tryfind(y)++c_preproc.c_parser = dumb_parser+new file mode 100644@@ -0,0 +1,308 @@+#! /usr/bin/env python+# encoding: utf-8+# Eclipse CDT 5.0 generator for Waf+# Richard Quirk 2009-1011 (New BSD License)+# Thomas Nagy 2011 (ported to Waf 1.6)++"""+Usage:++def options(opt):+ opt.load('eclipse')++$ waf configure eclipse+"""++import sys, os+from waflib import Utils, Logs, Context, Options, Build, TaskGen, Scripting+from xml.dom.minidom import Document++oe_cdt = 'org.eclipse.cdt'+cdt_mk = oe_cdt + '.make.core'+cdt_core = oe_cdt + '.core'+cdt_bld = oe_cdt + '.build.core'++class eclipse(Build.BuildContext):+ cmd = 'eclipse'+ fun = Scripting.default_cmd++ def execute(self):+ """+ Entry point+ """+ self.restore()+ if not self.all_envs:+ self.load_envs()+ self.recurse([self.run_dir])++ appname = getattr(Context.g_module, Context.APPNAME, os.path.basename(self.srcnode.abspath()))+ self.create_cproject(appname, pythonpath=self.env['ECLIPSE_PYTHON_PATH'])++ def create_cproject(self, appname, workspace_includes=[], pythonpath=[]):+ """+ Create the Eclipse CDT .project and .cproject files+ @param appname The name that will appear in the Project Explorer+ @param build The BuildContext object to extract includes from+ @param workspace_includes Optional project includes to prevent+ "Unresolved Inclusion" errors in the Eclipse editor+ @param pythonpath Optional project specific python paths+ """+ source_dirs = []+ cpppath = self.env['CPPPATH']+ Logs.warn('Generating Eclipse CDT project files')++ for g in self.groups:+ for tg in g:+ if not isinstance(tg, TaskGen.task_gen):+ continue++ tg.post()+ if not getattr(tg, 'link_task', None):+ continue++ l = Utils.to_list(getattr(tg, "includes", ''))+ sources = Utils.to_list(getattr(tg, 'source', ''))+ features = Utils.to_list(getattr(tg, 'features', ''))++ is_cc = 'c' in features or 'cxx' in features++ bldpath = tg.path.bldpath()++ base = os.path.normpath(os.path.join(self.bldnode.name, tg.path.srcpath()))++ if is_cc:+ sources_dirs = set([src.parent for src in tg.to_nodes(sources)])++ incnodes = tg.to_incnodes(tg.to_list(getattr(tg, 'includes', [])) + tg.env['INCLUDES'])+ for p in incnodes:+ path = p.path_from(self.srcnode)+ workspace_includes.append(path)++ if is_cc and path not in source_dirs:+ source_dirs.append(path)++ project = self.impl_create_project(sys.executable, appname)+ self.srcnode.make_node('.project').write(project.toprettyxml())++ waf = os.path.abspath(sys.argv[0])+ project = self.impl_create_cproject(sys.executable, waf, appname, workspace_includes, cpppath, source_dirs)+ self.srcnode.make_node('.cproject').write(project.toprettyxml())++ project = self.impl_create_pydevproject(appname, sys.path, pythonpath)+ self.srcnode.make_node('.pydevproject').write(project.toprettyxml())++ def impl_create_project(self, executable, appname):+ doc = Document()+ projectDescription = doc.createElement('projectDescription')+ self.add(doc, projectDescription, 'name', appname)+ self.add(doc, projectDescription, 'comment')+ self.add(doc, projectDescription, 'projects')+ buildSpec = self.add(doc, projectDescription, 'buildSpec')+ buildCommand = self.add(doc, buildSpec, 'buildCommand')+ self.add(doc, buildCommand, 'name', oe_cdt + '.managedbuilder.core.genmakebuilder')+ self.add(doc, buildCommand, 'triggers', 'clean,full,incremental,')+ arguments = self.add(doc, buildCommand, 'arguments')+ # the default make-style targets are overwritten by the .cproject values+ dictionaries = {+ cdt_mk + '.contents': cdt_mk + '.activeConfigSettings',+ cdt_mk + '.enableAutoBuild': 'false',+ cdt_mk + '.enableCleanBuild': 'true',+ cdt_mk + '.enableFullBuild': 'true',+ }+ for k, v in dictionaries.items():+ self.addDictionary(doc, arguments, k, v)++ natures = self.add(doc, projectDescription, 'natures')+ nature_list = """+ core.ccnature+ managedbuilder.core.ScannerConfigNature+ managedbuilder.core.managedBuildNature+ core.cnature+ """.split()+ for n in nature_list:+ self.add(doc, natures, 'nature', oe_cdt + '.' + n)++ self.add(doc, natures, 'nature', 'org.python.pydev.pythonNature')++ doc.appendChild(projectDescription)+ return doc++ def impl_create_cproject(self, executable, waf, appname, workspace_includes, cpppath, source_dirs=[]):+ doc = Document()+ doc.appendChild(doc.createProcessingInstruction('fileVersion', '4.0.0'))+ cconf_id = cdt_core + '.default.config.1'+ cproject = doc.createElement('cproject')+ storageModule = self.add(doc, cproject, 'storageModule',+ {'moduleId': cdt_core + '.settings'})+ cconf = self.add(doc, storageModule, 'cconfiguration', {'id':cconf_id})++ storageModule = self.add(doc, cconf, 'storageModule',+ {'buildSystemId': oe_cdt + '.managedbuilder.core.configurationDataProvider',+ 'id': cconf_id,+ 'moduleId': cdt_core + '.settings',+ 'name': 'Default'})++ self.add(doc, storageModule, 'externalSettings')++ extensions = self.add(doc, storageModule, 'extensions')+ extension_list = """+ VCErrorParser+ MakeErrorParser+ GCCErrorParser+ GASErrorParser+ GLDErrorParser+ """.split()+ ext = self.add(doc, extensions, 'extension',+ {'id': cdt_core + '.ELF', 'point':cdt_core + '.BinaryParser'})+ for e in extension_list:+ ext = self.add(doc, extensions, 'extension',+ {'id': cdt_core + '.' + e, 'point':cdt_core + '.ErrorParser'})++ storageModule = self.add(doc, cconf, 'storageModule',+ {'moduleId': 'cdtBuildSystem', 'version': '4.0.0'})+ config = self.add(doc, storageModule, 'configuration',+ {'artifactName': appname,+ 'id': cconf_id,+ 'name': 'Default',+ 'parent': cdt_bld + '.prefbase.cfg'})+ folderInfo = self.add(doc, config, 'folderInfo',+ {'id': cconf_id+'.', 'name': '/', 'resourcePath': ''})++ toolChain = self.add(doc, folderInfo, 'toolChain',+ {'id': cdt_bld + '.prefbase.toolchain.1',+ 'name': 'No ToolChain',+ 'resourceTypeBasedDiscovery': 'false',+ 'superClass': cdt_bld + '.prefbase.toolchain'})++ targetPlatform = self.add(doc, toolChain, 'targetPlatform',+ { 'binaryParser': 'org.eclipse.cdt.core.ELF',+ 'id': cdt_bld + '.prefbase.toolchain.1', 'name': ''})++ waf_build = '"%s" %s'%(waf, eclipse.fun)+ waf_clean = '"%s" clean'%(waf)+ builder = self.add(doc, toolChain, 'builder',+ {'autoBuildTarget': waf_build,+ 'command': executable,+ 'enableAutoBuild': 'false',+ 'cleanBuildTarget': waf_clean,+ 'enableIncrementalBuild': 'true',+ 'id': cdt_bld + '.settings.default.builder.1',+ 'incrementalBuildTarget': waf_build,+ 'managedBuildOn': 'false',+ 'name': 'Gnu Make Builder',+ 'superClass': cdt_bld + '.settings.default.builder'})++ for tool_name in ("Assembly", "GNU C++", "GNU C"):+ tool = self.add(doc, toolChain, 'tool',+ {'id': cdt_bld + '.settings.holder.1',+ 'name': tool_name,+ 'superClass': cdt_bld + '.settings.holder'})+ if cpppath or workspace_includes:+ incpaths = cdt_bld + '.settings.holder.incpaths'+ option = self.add(doc, tool, 'option',+ {'id': incpaths+'.1',+ 'name': 'Include Paths',+ 'superClass': incpaths,+ 'valueType': 'includePath'})+ for i in workspace_includes:+ self.add(doc, option, 'listOptionValue',+ {'builtIn': 'false',+ 'value': '"${workspace_loc:/%s/%s}"'%(appname, i)})+ for i in cpppath:+ self.add(doc, option, 'listOptionValue',+ {'builtIn': 'false',+ 'value': '"%s"'%(i)})+ if source_dirs:+ sourceEntries = self.add(doc, config, 'sourceEntries')+ for i in source_dirs:+ self.add(doc, sourceEntries, 'entry',+ {'excluding': i,+ 'flags': 'VALUE_WORKSPACE_PATH|RESOLVED',+ 'kind': 'sourcePath',+ 'name': ''})+ self.add(doc, sourceEntries, 'entry',+ {+ 'flags': 'VALUE_WORKSPACE_PATH|RESOLVED',+ 'kind': 'sourcePath',+ 'name': i})++ storageModule = self.add(doc, cconf, 'storageModule',+ {'moduleId': cdt_mk + '.buildtargets'})+ buildTargets = self.add(doc, storageModule, 'buildTargets')+ def addTargetWrap(name, runAll):+ return self.addTarget(doc, buildTargets, executable, name,+ '"%s" %s'%(waf, name), runAll)+ addTargetWrap('configure', True)+ addTargetWrap('dist', False)+ addTargetWrap('install', False)+ addTargetWrap('check', False)++ storageModule = self.add(doc, cproject, 'storageModule',+ {'moduleId': 'cdtBuildSystem',+ 'version': '4.0.0'})++ project = self.add(doc, storageModule, 'project',+ {'id': '%s.null.1'%appname, 'name': appname})++ doc.appendChild(cproject)+ return doc++ def impl_create_pydevproject(self, appname, system_path, user_path):+ # create a pydevproject file+ doc = Document()+ doc.appendChild(doc.createProcessingInstruction('eclipse-pydev', 'version="1.0"'))+ pydevproject = doc.createElement('pydev_project')+ prop = self.add(doc, pydevproject,+ 'pydev_property',+ 'python %d.%d'%(sys.version_info[0], sys.version_info[1]))+ prop.setAttribute('name', 'org.python.pydev.PYTHON_PROJECT_VERSION')+ prop = self.add(doc, pydevproject, 'pydev_property', 'Default')+ prop.setAttribute('name', 'org.python.pydev.PYTHON_PROJECT_INTERPRETER')+ # add waf's paths+ wafadmin = [p for p in system_path if p.find('wafadmin') != -1]+ if wafadmin:+ prop = self.add(doc, pydevproject, 'pydev_pathproperty',+ {'name':'org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH'})+ for i in wafadmin:+ self.add(doc, prop, 'path', i)+ if user_path:+ prop = self.add(doc, pydevproject, 'pydev_pathproperty',+ {'name':'org.python.pydev.PROJECT_SOURCE_PATH'})+ for i in user_path:+ self.add(doc, prop, 'path', '/'+appname+'/'+i)++ doc.appendChild(pydevproject)+ return doc++ def addDictionary(self, doc, parent, k, v):+ dictionary = self.add(doc, parent, 'dictionary')+ self.add(doc, dictionary, 'key', k)+ self.add(doc, dictionary, 'value', v)+ return dictionary++ def addTarget(self, doc, buildTargets, executable, name, buildTarget, runAllBuilders=True):+ target = self.add(doc, buildTargets, 'target',+ {'name': name,+ 'path': '',+ 'targetID': oe_cdt + '.build.MakeTargetBuilder'})+ self.add(doc, target, 'buildCommand', executable)+ self.add(doc, target, 'buildArguments', None)+ self.add(doc, target, 'buildTarget', buildTarget)+ self.add(doc, target, 'stopOnError', 'true')+ self.add(doc, target, 'useDefaultCommand', 'false')+ self.add(doc, target, 'runAllBuilders', str(runAllBuilders).lower())++ def add(self, doc, parent, tag, value = None):+ el = doc.createElement(tag)+ if (value):+ if type(value) == type(str()):+ el.appendChild(doc.createTextNode(value))+ elif type(value) == type(dict()):+ self.setAttributes(el, value)+ parent.appendChild(el)+ return el++ def setAttributes(self, node, attrs):+ for k, v in attrs.items():+ node.setAttribute(k, v)+new file mode 100644@@ -0,0 +1,19 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010 (ita)++"""+Erlang support+"""++from waflib import TaskGen++TaskGen.declare_chain(name = 'erlc',+ rule = '${ERLC} ${ERLC_FLAGS} ${SRC[0].abspath()} -o ${TGT[0].name}',+ ext_in = '.erl',+ ext_out = '.beam')++def configure(conf):+ conf.find_program('erlc', var='ERLC')+ conf.env.ERLC_FLAGS = []+new file mode 100644@@ -0,0 +1,34 @@+#! /usr/bin/env python+# encoding: utf-8+# harald at klimachs.de++import re+from waflib.Tools import fc, fc_config, fc_scan+from waflib.Configure import conf++from waflib.Tools.compiler_fc import fc_compiler+fc_compiler['linux'].insert(0, 'fc_bgxlf')++@conf+def find_bgxlf(conf):+ fc = conf.find_program(['bgxlf2003_r','bgxlf2003'], var='FC')+ fc = conf.cmd_to_list(fc)+ conf.get_xlf_version(fc)+ conf.env.FC_NAME = 'BGXLF'++@conf+def bg_flags(self):+ self.env.SONAME_ST = ''+ self.env.FCSHLIB_MARKER = ''+ self.env.FCSTLIB_MARKER = ''+ self.env.FCFLAGS_fcshlib = ['-fPIC']+ self.env.LINKFLAGS_fcshlib = ['-G', '-Wl,-bexpfull']++def configure(conf):+ conf.find_bgxlf()+ conf.find_ar()+ conf.fc_flags()+ conf.fc_add_flags()+ conf.xlf_flags()+ conf.bg_flags()+new file mode 100644@@ -0,0 +1,51 @@+#! /usr/bin/env python+# encoding: utf-8+# harald at klimachs.de++import re+from waflib import Utils+from waflib.Tools import fc, fc_config, fc_scan+from waflib.Configure import conf++from waflib.Tools.compiler_fc import fc_compiler+fc_compiler['linux'].append('fc_cray')++@conf+def find_crayftn(conf):+ """Find the Cray fortran compiler (will look in the environment variable 'FC')"""+ fc = conf.find_program(['crayftn'], var='FC')+ fc = conf.cmd_to_list(fc)+ conf.get_crayftn_version(fc)+ conf.env.FC_NAME = 'CRAY'+ conf.env.FC_MOD_CAPITALIZATION = 'UPPER.mod'++@conf+def crayftn_flags(conf):+ v = conf.env+ v['_FCMODOUTFLAGS'] = ['-em', '-J.'] # enable module files and put them in the current directoy+ v['FCFLAGS_DEBUG'] = ['-m1'] # more verbose compiler warnings+ v['FCFLAGS_fcshlib'] = ['-h pic']+ v['LINKFLAGS_fcshlib'] = ['-h shared']++ v['FCSTLIB_MARKER'] = '-h static'+ v['FCSHLIB_MARKER'] = '-h dynamic'++@conf+def get_crayftn_version(conf, fc):+ version_re = re.compile(r"Cray Fortran\s*:\s*Version\s*(?P<major>\d*)\.(?P<minor>\d*)", re.I).search+ cmd = fc + ['-V']+ out,err = fc_config.getoutput(conf, cmd, stdin=False)+ if out: match = version_re(out)+ else: match = version_re(err)+ if not match:+ conf.fatal('Could not determine the Cray Fortran compiler version.')+ k = match.groupdict()+ conf.env['FC_VERSION'] = (k['major'], k['minor'])++def configure(conf):+ conf.find_crayftn()+ conf.find_ar()+ conf.fc_flags()+ conf.fc_add_flags()+ conf.crayftn_flags()+new file mode 100644@@ -0,0 +1,60 @@+#! /usr/bin/env python+# encoding: utf-8+# harald at klimachs.de++import re+from waflib import Utils+from waflib.Tools import fc,fc_config,fc_scan+from waflib.Configure import conf++from waflib.Tools.compiler_fc import fc_compiler+fc_compiler['linux'].insert(0, 'fc_nag')++@conf+def find_nag(conf):+ """Find the NAG Fortran Compiler (will look in the environment variable 'FC')"""++ fc = conf.find_program(['nagfor'], var='FC')+ fc = conf.cmd_to_list(fc)+ conf.get_nag_version(fc)+ conf.env.FC_NAME = 'NAG'+ conf.env.FC_MOD_CAPITALIZATION = 'lower'++@conf+def nag_flags(conf):+ v = conf.env+ v['FCFLAGS_DEBUG'] = ['-C=all']++@conf+def nag_modifier_platform(conf):+ dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()+ nag_modifier_func = getattr(conf, 'nag_modifier_' + dest_os, None)+ if nag_modifier_func:+ nag_modifier_func()++@conf+def get_nag_version(conf, fc):+ """Get the NAG compiler version"""++ version_re = re.compile(r"^NAG Fortran Compiler *Release *(?P<major>\d*)\.(?P<minor>\d*)", re.M).search+ cmd = fc + ['-v']++ out, err = fc_config.getoutput(conf,cmd,stdin=False)+ if out:+ match = version_re(out)+ if not match:+ match = version_re(err)+ else: match = version_re(err)+ if not match:+ conf.fatal('Could not determine the NAG version.')+ k = match.groupdict()+ conf.env['FC_VERSION'] = (k['major'], k['minor'])++def configure(conf):+ conf.find_nag()+ conf.find_ar()+ conf.fc_flags()+ conf.fc_add_flags()+ conf.nag_flags()+ conf.nag_modifier_platform()+new file mode 100644@@ -0,0 +1,57 @@+#! /usr/bin/env python+# encoding: utf-8+# harald at klimachs.de++import re+from waflib import Utils+from waflib.Tools import fc,fc_config,fc_scan+from waflib.Configure import conf++from waflib.Tools.compiler_fc import fc_compiler+fc_compiler['linux'].insert(0, 'fc_open64')++@conf+def find_openf95(conf):+ """Find the Open64 Fortran Compiler (will look in the environment variable 'FC')"""++ fc = conf.find_program(['openf95', 'openf90'], var='FC')+ fc = conf.cmd_to_list(fc)+ conf.get_open64_version(fc)+ conf.env.FC_NAME = 'OPEN64'+ conf.env.FC_MOD_CAPITALIZATION = 'UPPER.mod'++@conf+def openf95_flags(conf):+ v = conf.env+ v['FCFLAGS_DEBUG'] = ['-fullwarn']++@conf+def openf95_modifier_platform(conf):+ dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()+ openf95_modifier_func = getattr(conf, 'openf95_modifier_' + dest_os, None)+ if openf95_modifier_func:+ openf95_modifier_func()++@conf+def get_open64_version(conf, fc):+ """Get the Open64 compiler version"""++ version_re = re.compile(r"Open64 Compiler Suite: *Version *(?P<major>\d*)\.(?P<minor>\d*)", re.I).search+ cmd = fc + ['-version']++ out, err = fc_config.getoutput(conf,cmd,stdin=False)+ if out: match = version_re(out)+ else: match = version_re(err)+ if not match:+ conf.fatal('Could not determine the Open64 version.')+ k = match.groupdict()+ conf.env['FC_VERSION'] = (k['major'], k['minor'])++def configure(conf):+ conf.find_openf95()+ conf.find_ar()+ conf.fc_flags()+ conf.fc_add_flags()+ conf.openf95_flags()+ conf.openf95_modifier_platform()+new file mode 100644@@ -0,0 +1,66 @@+#! /usr/bin/env python+# encoding: utf-8+# harald at klimachs.de++import re+from waflib import Utils+from waflib.Tools import fc, fc_config, fc_scan+from waflib.Configure import conf++from waflib.Tools.compiler_fc import fc_compiler+fc_compiler['linux'].append('fc_pgfortran')++@conf+def find_pgfortran(conf):+ """Find the PGI fortran compiler (will look in the environment variable 'FC')"""+ fc = conf.find_program(['pgfortran', 'pgf95', 'pgf90'], var='FC')+ fc = conf.cmd_to_list(fc)+ conf.get_pgfortran_version(fc)+ conf.env.FC_NAME = 'PGFC'++@conf+def pgfortran_flags(conf):+ v = conf.env+ v['FCFLAGS_fcshlib'] = ['-shared']+ v['FCFLAGS_DEBUG'] = ['-Minform=inform', '-Mstandard'] # why not+ v['FCSTLIB_MARKER'] = '-Bstatic'+ v['FCSHLIB_MARKER'] = '-Bdynamic'+ v['SONAME_ST'] = '-soname %s'++@conf+def get_pgfortran_version(conf,fc):+ version_re = re.compile(r"The Portland Group", re.I).search+ cmd = fc + ['-V']+ out,err = fc_config.getoutput(conf, cmd, stdin=False)+ if out: match = version_re(out)+ else: match = version_re(err)+ if not match:+ conf.fatal('Could not verify PGI signature')+ cmd = fc + ['-help=variable']+ out,err = fc_config.getoutput(conf, cmd, stdin=False)+ if out.find('COMPVER')<0:+ conf.fatal('Could not determine the compiler type')+ k = {}+ prevk = ''+ out = out.split('\n')+ for line in out:+ lst = line.partition('=')+ if lst[1] == '=':+ key = lst[0].rstrip()+ if key == '': key = prevk+ val = lst[2].rstrip()+ k[key] = val+ else: prevk = line.partition(' ')[0]+ def isD(var):+ return var in k+ def isT(var):+ return var in k and k[var]!='0'+ conf.env['FC_VERSION'] = (k['COMPVER'].split('.'))++def configure(conf):+ conf.find_pgfortran()+ conf.find_ar()+ conf.fc_flags()+ conf.fc_add_flags()+ conf.pgfortran_flags()+new file mode 100644@@ -0,0 +1,61 @@+#! /usr/bin/env python+# encoding: utf-8+# harald at klimachs.de++import re+from waflib import Utils+from waflib.Tools import fc,fc_config,fc_scan+from waflib.Configure import conf++from waflib.Tools.compiler_fc import fc_compiler+fc_compiler['linux'].append('fc_solstudio')++@conf+def find_solstudio(conf):+ """Find the Solaris Studio compiler (will look in the environment variable 'FC')"""++ fc = conf.find_program(['sunf95', 'f95', 'sunf90', 'f90'], var='FC')+ fc = conf.cmd_to_list(fc)+ conf.get_solstudio_version(fc)+ conf.env.FC_NAME = 'SOL'++@conf+def solstudio_flags(conf):+ v = conf.env+ v['FCFLAGS_fcshlib'] = ['-Kpic']+ v['FCFLAGS_DEBUG'] = ['-w3']+ v['LINKFLAGS_fcshlib'] = ['-G']+ v['FCSTLIB_MARKER'] = '-Bstatic'+ v['FCSHLIB_MARKER'] = '-Bdynamic'+ v['SONAME_ST'] = '-h %s'++@conf+def solstudio_modifier_platform(conf):+ dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()+ solstudio_modifier_func = getattr(conf, 'solstudio_modifier_' + dest_os, None)+ if solstudio_modifier_func:+ solstudio_modifier_func()++@conf+def get_solstudio_version(conf, fc):+ """Get the compiler version"""++ version_re = re.compile(r"Sun Fortran 95 *(?P<major>\d*)\.(?P<minor>\d*)", re.I).search+ cmd = fc + ['-V']++ out, err = fc_config.getoutput(conf,cmd,stdin=False)+ if out: match = version_re(out)+ else: match = version_re(err)+ if not match:+ conf.fatal('Could not determine the Sun Studio Fortran version.')+ k = match.groupdict()+ conf.env['FC_VERSION'] = (k['major'], k['minor'])++def configure(conf):+ conf.find_solstudio()+ conf.find_ar()+ conf.fc_flags()+ conf.fc_add_flags()+ conf.solstudio_flags()+ conf.solstudio_modifier_platform()+new file mode 100644@@ -0,0 +1,64 @@+#! /usr/bin/env python+# encoding: utf-8+# harald at klimachs.de++import re+from waflib import Utils+from waflib.Tools import fc,fc_config,fc_scan+from waflib.Configure import conf++from waflib.Tools.compiler_fc import fc_compiler+fc_compiler['aix'].insert(0, 'fc_xlf')++@conf+def find_xlf(conf):+ """Find the xlf program (will look in the environment variable 'FC')"""++ fc = conf.find_program(['xlf2003_r', 'xlf2003', 'xlf95_r', 'xlf95', 'xlf90_r', 'xlf90', 'xlf_r', 'xlf'], var='FC')+ fc = conf.cmd_to_list(fc)+ conf.get_xlf_version(fc)+ conf.env.FC_NAME='XLF'++@conf+def xlf_flags(conf):+ v = conf.env+ v['FCDEFINES_ST'] = '-WF,-D%s'+ v['FCFLAGS_fcshlib'] = ['-qpic=small']+ v['FCFLAGS_DEBUG'] = ['-qhalt=w']+ v['LINKFLAGS_fcshlib'] = ['-Wl,-shared']++@conf+def xlf_modifier_platform(conf):+ dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform()+ xlf_modifier_func = getattr(conf, 'xlf_modifier_' + dest_os, None)+ if xlf_modifier_func:+ xlf_modifier_func()++@conf+def get_xlf_version(conf, fc):+ """Get the compiler version"""++ cmd = fc + ['-qversion']+ try:+ out, err = conf.cmd_and_log(cmd, output=0)+ except Errors.WafError:+ conf.fatal('Could not find xlf %r' % cmd)++ for v in (r"IBM XL Fortran.* V(?P<major>\d*)\.(?P<minor>\d*)"):+ version_re = re.compile(v, re.I).search+ match = version_re(out or err)+ if match:+ k = match.groupdict()+ conf.env['FC_VERSION'] = (k['major'], k['minor'])+ break+ else:+ conf.fatal('Could not determine the XLF version.')++def configure(conf):+ conf.find_xlf()+ conf.find_ar()+ conf.fc_flags()+ conf.fc_add_flags()+ conf.xlf_flags()+ conf.xlf_modifier_platform()+new file mode 100644@@ -0,0 +1,30 @@+#!/usr/bin/python+# encoding: utf-8+# Grygoriy Fuchedzhy 2009++"""+Compile fluid files (fltk graphic library). Use the 'fluid' feature in conjuction with the 'cxx' feature.+"""++from waflib import Task+from waflib.TaskGen import extension++class fluid(Task.Task):+ color = 'BLUE'+ ext_out = ['.h']+ run_str = '${FLUID} -c -o ${TGT[0].abspath()} -h ${TGT[1].abspath()} ${SRC}'++@extension('.fl')+def fluid(self, node):+ """add the .fl to the source list; the cxx file generated will be compiled when possible"""+ cpp = node.change_ext('.cpp')+ hpp = node.change_ext('.hpp')+ self.create_task('fluid', node, [cpp, hpp])++ if 'cxx' in self.features:+ self.source.append(cpp)++def configure(conf):+ conf.find_program('fluid', var='FLUID')+ conf.check_cfg(path='fltk-config', package='', args='--cxxflags --ldflags', uselib_store='FLTK', mandatory=True)+new file mode 100644@@ -0,0 +1,74 @@+#!/usr/bin/env python+# encoding: utf-8+#+# written by Sylvain Rouquette, 2011++'''+To add the freeimage tool to the waf file:+$ ./waf-light --tools=compat15,freeimage+ or, if you have waf >= 1.6.2+$ ./waf update --files=freeimage++The wscript will look like:++def options(opt):+ opt.load('compiler_cxx freeimage')++def configure(conf):+ conf.load('compiler_cxx freeimage')++ # you can call check_freeimage with some parameters.+ # It's optional on Linux, it's 'mandatory' on Windows if+ # you didn't use --fi-path on the command-line++ # conf.check_freeimage(path='FreeImage/Dist', fip=True)++def build(bld):+ bld(source='main.cpp', target='app', use='FREEIMAGE')+'''++from waflib import Utils+from waflib.Configure import conf+++def options(opt):+ opt.add_option('--fi-path', type='string', default='', dest='fi_path',+ help='''path to the FreeImage directory \+ where the files are e.g. /FreeImage/Dist''')+ opt.add_option('--fip', action='store_true', default=False, dest='fip',+ help='link with FreeImagePlus')+ opt.add_option('--fi-static', action='store_true',+ default=False, dest='fi_static',+ help="link as shared libraries")+++@conf+def check_freeimage(self, path=None, fip=False):+ self.start_msg('Checking FreeImage')+ if not self.env['CXX']:+ self.fatal('you must load compiler_cxx before loading freeimage')+ prefix = self.options.fi_static and 'ST' or ''+ platform = Utils.unversioned_sys_platform()+ if platform == 'win32':+ if not path:+ self.fatal('you must specify the path to FreeImage. \+ use --fi-path=/FreeImage/Dist')+ else:+ self.env['INCLUDES_FREEIMAGE'] = path+ self.env['%sLIBPATH_FREEIMAGE' % prefix] = path+ libs = ['FreeImage']+ if self.options.fip:+ libs.append('FreeImagePlus')+ if platform == 'win32':+ self.env['%sLIB_FREEIMAGE' % prefix] = libs+ else:+ self.env['%sLIB_FREEIMAGE' % prefix] = [i.lower() for i in libs]+ self.end_msg('ok')+++def configure(conf):+ platform = Utils.unversioned_sys_platform()+ if platform == 'win32' and not conf.options.fi_path:+ return+ conf.check_freeimage(conf.options.fi_path, conf.options.fip)+new file mode 100644@@ -0,0 +1,31 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2011 (ita)++"""+Fully sequential builds++The previous tasks from task generators are re-processed, and this may lead to speed issues+Yet, if you are using this, speed is probably a minor concern+"""++from waflib import Build++def options(opt):+ pass++def configure(conf):+ pass++class FSBContext(Build.BuildContext):+ def __call__(self, *k, **kw):+ ret = Build.BuildContext.__call__(self, *k, **kw)++ # evaluate the results immediately+ Build.BuildContext.compile(self)++ return ret++ def compile(self):+ pass+new file mode 100644@@ -0,0 +1,66 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2011 (ita)++"""+Experimental F# stuff++FSC="mono /path/to/fsc.exe" waf configure build+"""++from waflib import Utils, Task, Options, Logs, Errors+from waflib.TaskGen import before_method, after_method, feature+from waflib.Tools import ccroot, cs+from waflib.Configure import conf++ccroot.USELIB_VARS['fsc'] = set(['CSFLAGS', 'ASSEMBLIES', 'RESOURCES'])++@feature('fs')+@before_method('process_source')+def apply_fsc(self):+ cs_nodes = []+ no_nodes = []+ for x in self.to_nodes(self.source):+ if x.name.endswith('.fs'):+ cs_nodes.append(x)+ else:+ no_nodes.append(x)+ self.source = no_nodes++ bintype = getattr(self, 'type', self.gen.endswith('.dll') and 'library' or 'exe')+ self.cs_task = tsk = self.create_task('fsc', cs_nodes, self.path.find_or_declare(self.gen))+ tsk.env.CSTYPE = '/target:%s' % bintype+ tsk.env.OUT = '/out:%s' % tsk.outputs[0].abspath()++ inst_to = getattr(self, 'install_path', bintype=='exe' and '${BINDIR}' or '${LIBDIR}')+ if inst_to:+ # note: we are making a copy, so the files added to cs_task.outputs won't be installed automatically+ mod = getattr(self, 'chmod', bintype=='exe' and Utils.O755 or Utils.O644)+ self.install_task = self.bld.install_files(inst_to, self.cs_task.outputs[:], env=self.env, chmod=mod)++feature('fs')(cs.use_cs)+after_method('apply_fsc')(cs.use_cs)++feature('fs')(cs.debug_cs)+after_method('apply_fsc', 'use_cs')(cs.debug_cs)++class fsc(Task.Task):+ """+ Compile F# files+ """+ color = 'YELLOW'+ run_str = '${FSC} ${CSTYPE} ${CSFLAGS} ${ASS_ST:ASSEMBLIES} ${RES_ST:RESOURCES} ${OUT} ${SRC}'++def configure(conf):+ """+ Find a F# compiler, set the variable FSC for the compiler and FS_NAME (mono or fsc)+ """+ conf.find_program(['fsc.exe', 'fsharpc'], var='FSC')+ conf.env.FSC = conf.cmd_to_list(conf.env.FSC)+ conf.env.ASS_ST = '/r:%s'+ conf.env.RES_ST = '/resource:%s'++ conf.env.FS_NAME = 'fsc'+ if str(conf.env.FSC).lower().find('fsharpc') > -1:+ conf.env.FS_NAME = 'mono'+new file mode 100644@@ -0,0 +1,172 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2008-2010 (ita)++"""+Execute the tasks with gcc -MD, read the dependencies from the .d file+and prepare the dependency calculation for the next run+"""++import os, re, threading+from waflib import Task, Logs, Utils, Errors+from waflib.Tools import c_preproc+from waflib.TaskGen import before_method, feature++lock = threading.Lock()++preprocessor_flag = '-MD'++# Third-party tools are allowed to add extra names in here with append()+supported_compilers = ['gcc', 'icc']++@feature('c')+@before_method('process_source')+def add_mmd_cc(self):+ if self.env.CC_NAME in supported_compilers and self.env.get_flat('CFLAGS').find(preprocessor_flag) < 0:+ self.env.append_value('CFLAGS', [preprocessor_flag])++@feature('cxx')+@before_method('process_source')+def add_mmd_cxx(self):+ if self.env.CC_NAME in supported_compilers and self.env.get_flat('CXXFLAGS').find(preprocessor_flag) < 0:+ self.env.append_value('CXXFLAGS', [preprocessor_flag])++def scan(self):+ "the scanner does not do anything initially"+ if self.env.CC_NAME not in supported_compilers:+ return self.no_gccdeps_scan()+ nodes = self.generator.bld.node_deps.get(self.uid(), [])+ names = []+ return (nodes, names)++re_o = re.compile("\.o$")+re_splitter = re.compile(r'(?<!\\)\s+') # split by space, except when spaces are escaped++def remove_makefile_rule_lhs(line):+ # Splitting on a plain colon would accidentally match inside a+ # Windows absolute-path filename, so we must search for a colon+ # followed by whitespace to find the divider between LHS and RHS+ # of the Makefile rule.+ rulesep = ': '++ sep_idx = line.find(rulesep)+ if sep_idx >= 0:+ return line[sep_idx + 2:]+ else:+ return line++def post_run(self):+ # The following code is executed by threads, it is not safe, so a lock is needed...++ if self.env.CC_NAME not in supported_compilers:+ return self.no_gccdeps_post_run()++ if getattr(self, 'cached', None):+ return Task.Task.post_run(self)++ name = self.outputs[0].abspath()+ name = re_o.sub('.d', name)+ txt = Utils.readf(name)+ #os.unlink(name)++ # Compilers have the choice to either output the file's dependencies+ # as one large Makefile rule:+ #+ # /path/to/file.o: /path/to/dep1.h \+ # /path/to/dep2.h \+ # /path/to/dep3.h \+ # ...+ #+ # or as many individual rules:+ #+ # /path/to/file.o: /path/to/dep1.h+ # /path/to/file.o: /path/to/dep2.h+ # /path/to/file.o: /path/to/dep3.h+ # ...+ #+ # So the first step is to sanitize the input by stripping out the left-+ # hand side of all these lines. After that, whatever remains are the+ # implicit dependencies of task.outputs[0]+ txt = '\n'.join([remove_makefile_rule_lhs(line) for line in txt.splitlines()])++ # Now join all the lines together+ txt = txt.replace('\\\n', '')++ val = txt.strip()+ lst = val.split(':')+ val = [x.replace('\\ ', ' ') for x in re_splitter.split(val) if x]++ nodes = []+ bld = self.generator.bld++ for x in val:++ node = None+ if os.path.isabs(x):+ lock.acquire()+ try:+ node = bld.root.find_resource(x)+ finally:+ lock.release()+ else:+ path = bld.bldnode+ x = [k for k in Utils.split_path(x) if k and k != '.']+ while lst and x[0] == '..':+ x = x[1:]+ path = path.parent++ # when calling find_resource, make sure the path does not begin by '..'+ try:+ lock.acquire()+ node = path.find_resource(x)+ finally:+ lock.release()++ if not node:+ raise ValueError('could not find %r for %r' % (x, self))+ else:+ if not c_preproc.go_absolute:+ if not (node.is_child_of(bld.srcnode) or node.is_child_of(bld.bldnode)):+ continue++ if id(node) == id(self.inputs[0]):+ # ignore the source file, it is already in the dependencies+ # this way, successful config tests may be retrieved from the cache+ continue++ nodes.append(node)++ Logs.debug('deps: real scanner for %s returned %s' % (str(self), str(nodes)))++ bld.node_deps[self.uid()] = nodes+ bld.raw_deps[self.uid()] = []++ try:+ del self.cache_sig+ except:+ pass++ Task.Task.post_run(self)++def sig_implicit_deps(self):+ if self.env.CC_NAME not in supported_compilers:+ return self.no_gccdeps_sig_implicit_deps()+ try:+ return Task.Task.sig_implicit_deps(self)+ except Errors.WafError:+ return Utils.SIG_NIL++for name in 'c cxx'.split():+ try:+ cls = Task.classes[name]+ except KeyError:+ pass+ else:+ cls.no_gccdeps_post_run = cls.post_run+ cls.no_gccdeps_scan = cls.scan+ cls.no_gccdeps_sig_implicit_deps = cls.sig_implicit_deps++ cls.post_run = post_run+ cls.scan = scan+ cls.sig_implicit_deps = sig_implicit_deps+new file mode 100644@@ -0,0 +1,257 @@+#!/usr/bin/env python+# encoding: utf-8+# Tom Wambold tom5760 gmail.com 2009+# Thomas Nagy 2010++"""+Go as a language may look nice, but its toolchain is one of the worse a developer+has ever seen. It keeps changing though, and I would like to believe that it will get+better eventually, but the crude reality is that this tool and the examples are+getting broken every few months.++If you have been lured into trying to use Go, you should stick to their Makefiles.+"""++import os, platform++from waflib import Utils, Task, TaskGen+from waflib.TaskGen import feature, extension, after_method, before_method+from waflib.Tools.ccroot import link_task, stlink_task, propagate_uselib_vars, process_use++class go(Task.Task):+ run_str = '${GOC} ${GOCFLAGS} ${CPPPATH_ST:INCPATHS} -o ${TGT} ${SRC}'++class gopackage(stlink_task):+ run_str = '${GOP} grc ${TGT} ${SRC}'++class goprogram(link_task):+ run_str = '${GOL} ${GOLFLAGS} -o ${TGT} ${SRC}'+ inst_to = '${BINDIR}'+ chmod = Utils.O755++class cgopackage(stlink_task):+ color = 'YELLOW'+ inst_to = '${LIBDIR}'+ ext_in = ['.go']+ ext_out = ['.a']++ def run(self):+ src_dir = self.generator.bld.path+ source = self.inputs+ target = self.outputs[0].change_ext('')++ #print ("--> %s" % self.outputs)+ #print ('++> %s' % self.outputs[1])+ bld_dir = self.outputs[1]+ bld_dir.mkdir()+ obj_dir = bld_dir.make_node('_obj')+ obj_dir.mkdir()++ bld_srcs = []+ for s in source:+ # FIXME: it seems gomake/cgo stumbles on filenames like a/b/c.go+ # -> for the time being replace '/' with '_'...+ #b = bld_dir.make_node(s.path_from(src_dir))+ b = bld_dir.make_node(s.path_from(src_dir).replace(os.sep,'_'))+ b.parent.mkdir()+ #print ('++> %s' % (s.path_from(src_dir),))+ try:+ try:os.remove(b.abspath())+ except Exception:pass+ os.symlink(s.abspath(), b.abspath())+ except Exception:+ # if no support for symlinks, copy the file from src+ b.write(s.read())+ bld_srcs.append(b)+ #print("--|> [%s]" % b.abspath())+ b.sig = Utils.h_file(b.abspath())+ pass+ #self.set_inputs(bld_srcs)+ #self.generator.bld.raw_deps[self.uid()] = [self.signature()] + bld_srcs+ makefile_node = bld_dir.make_node("Makefile")+ makefile_tmpl = '''\+# Copyright 2009 The Go Authors. All rights reserved.+# Use of this source code is governed by a BSD-style+# license that can be found in the LICENSE file. ---++include $(GOROOT)/src/Make.inc++TARG=%(target)s++GCIMPORTS= %(gcimports)s++CGOFILES=\\+\t%(source)s++CGO_CFLAGS= %(cgo_cflags)s++CGO_LDFLAGS= %(cgo_ldflags)s++include $(GOROOT)/src/Make.pkg++%%: install %%.go+ $(GC) $*.go+ $(LD) -o $@ $*.$O++''' % {+'gcimports': ' '.join(l for l in self.env['GOCFLAGS']),+'cgo_cflags' : ' '.join(l for l in self.env['GOCFLAGS']),+'cgo_ldflags': ' '.join(l for l in self.env['GOLFLAGS']),+'target': target.path_from(obj_dir),+'source': ' '.join([b.path_from(bld_dir) for b in bld_srcs])+}+ makefile_node.write(makefile_tmpl)+ #print ("::makefile: %s"%makefile_node.abspath())+ cmd = Utils.subst_vars('gomake ${GOMAKE_FLAGS}', self.env).strip()+ o = self.outputs[0].change_ext('.gomake.log')+ fout_node = bld_dir.find_or_declare(o.name)+ fout = open(fout_node.abspath(), 'w')+ rc = self.generator.bld.exec_command(+ cmd,+ stdout=fout,+ stderr=fout,+ cwd=bld_dir.abspath(),+ )+ if rc != 0:+ import waflib.Logs as msg+ msg.error('** error running [%s] (cgo-%s)' % (cmd, target))+ msg.error(fout_node.read())+ return rc+ self.generator.bld.read_stlib(+ target,+ paths=[obj_dir.abspath(),],+ )+ tgt = self.outputs[0]+ if tgt.parent != obj_dir:+ install_dir = os.path.join('${LIBDIR}',+ tgt.parent.path_from(obj_dir))+ else:+ install_dir = '${LIBDIR}'+ #print('===> %s (%s)' % (tgt.abspath(), install_dir))+ self.generator.bld.install_files(+ install_dir,+ tgt.abspath(),+ relative_trick=False,+ postpone=False,+ )+ return rc++@extension('.go')+def compile_go(self, node):+ #print('*'*80, self.name)+ if not ('cgopackage' in self.features):+ return self.create_compiled_task('go', node)+ #print ('compile_go-cgo...')+ bld_dir = node.parent.get_bld()+ obj_dir = bld_dir.make_node('_obj')+ target = obj_dir.make_node(node.change_ext('.a').name)+ return self.create_task('cgopackage', node, node.change_ext('.a'))++@feature('gopackage', 'goprogram', 'cgopackage')+@before_method('process_source')+def go_compiler_is_foobar(self):+ if self.env.GONAME == 'gcc':+ return+ self.source = self.to_nodes(self.source)+ src = []+ go = []+ for node in self.source:+ if node.name.endswith('.go'):+ go.append(node)+ else:+ src.append(node)+ self.source = src+ if not ('cgopackage' in self.features):+ #print('--> [%s]... (%s)' % (go[0], getattr(self, 'target', 'N/A')))+ tsk = self.create_compiled_task('go', go[0])+ tsk.inputs.extend(go[1:])+ else:+ #print ('+++ [%s] +++' % self.target)+ bld_dir = self.path.get_bld().make_node('cgopackage--%s' % self.target.replace(os.sep,'_'))+ obj_dir = bld_dir.make_node('_obj')+ target = obj_dir.make_node(self.target+'.a')+ tsk = self.create_task('cgopackage', go, [target, bld_dir])+ self.link_task = tsk++@feature('gopackage', 'goprogram', 'cgopackage')+@after_method('process_source', 'apply_incpaths',)+def go_local_libs(self):+ names = self.to_list(getattr(self, 'use', []))+ #print ('== go-local-libs == [%s] == use: %s' % (self.name, names))+ for name in names:+ tg = self.bld.get_tgen_by_name(name)+ if not tg:+ raise Utils.WafError('no target of name %r necessary for %r in go uselib local' % (name, self))+ tg.post()+ #print ("-- tg[%s]: %s" % (self.name,name))+ lnk_task = getattr(tg, 'link_task', None)+ if lnk_task:+ for tsk in self.tasks:+ if isinstance(tsk, (go, gopackage, cgopackage)):+ tsk.set_run_after(lnk_task)+ tsk.dep_nodes.extend(lnk_task.outputs)+ path = lnk_task.outputs[0].parent.abspath()+ if isinstance(lnk_task, (go, gopackage)):+ # handle hierarchical packages+ path = lnk_task.generator.path.get_bld().abspath()+ elif isinstance(lnk_task, (cgopackage,)):+ # handle hierarchical cgopackages+ cgo_obj_dir = lnk_task.outputs[1].find_or_declare('_obj')+ path = cgo_obj_dir.abspath()+ # recursively add parent GOCFLAGS...+ self.env.append_unique('GOCFLAGS',+ getattr(lnk_task.env, 'GOCFLAGS',[]))+ # ditto for GOLFLAGS...+ self.env.append_unique('GOLFLAGS',+ getattr(lnk_task.env, 'GOLFLAGS',[]))+ self.env.append_unique('GOCFLAGS', ['-I%s' % path])+ self.env.append_unique('GOLFLAGS', ['-L%s' % path])+ for n in getattr(tg, 'includes_nodes', []):+ self.env.append_unique('GOCFLAGS', ['-I%s' % n.abspath()])+ pass+ pass++def configure(conf):++ def set_def(var, val):+ if not conf.env[var]:+ conf.env[var] = val++ goarch = os.getenv('GOARCH')+ if goarch == '386':+ set_def('GO_PLATFORM', 'i386')+ elif goarch == 'amd64':+ set_def('GO_PLATFORM', 'x86_64')+ elif goarch == 'arm':+ set_def('GO_PLATFORM', 'arm')+ else:+ set_def('GO_PLATFORM', platform.machine())++ if conf.env.GO_PLATFORM == 'x86_64':+ set_def('GO_COMPILER', '6g')+ set_def('GO_LINKER', '6l')+ elif conf.env.GO_PLATFORM in ['i386', 'i486', 'i586', 'i686']:+ set_def('GO_COMPILER', '8g')+ set_def('GO_LINKER', '8l')+ elif conf.env.GO_PLATFORM == 'arm':+ set_def('GO_COMPILER', '5g')+ set_def('GO_LINKER', '5l')+ set_def('GO_EXTENSION', '.5')++ if not (conf.env.GO_COMPILER or conf.env.GO_LINKER):+ raise conf.fatal('Unsupported platform ' + platform.machine())++ set_def('GO_PACK', 'gopack')+ set_def('gopackage_PATTERN', '%s.a')+ set_def('CPPPATH_ST', '-I%s')++ set_def('GOMAKE_FLAGS', ['--quiet'])+ conf.find_program(conf.env.GO_COMPILER, var='GOC')+ conf.find_program(conf.env.GO_LINKER, var='GOL')+ conf.find_program(conf.env.GO_PACK, var='GOP')++ conf.find_program('cgo', var='CGO')++TaskGen.feature('go')(process_use)+TaskGen.feature('go')(propagate_uselib_vars)+new file mode 100644@@ -0,0 +1,17 @@+#!/usr/bin/env python+# encoding: utf-8+# Ali Sabil, 2007++from waflib import TaskGen++TaskGen.declare_chain(+ name = 'gob2',+ rule = '${GOB2} -o ${TGT[0].bld_dir()} ${GOB2FLAGS} ${SRC}',+ ext_in = '.gob',+ ext_out = '.c'+)++def configure(conf):+ conf.find_program('gob2', var='GOB2')+ conf.env['GOB2FLAGS'] = ''+new file mode 100644@@ -0,0 +1,19 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2011 (ita)++from waflib.TaskGen import after_method, feature++@after_method('propagate_uselib_vars')+@feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib', 'fcprogram', 'fcshlib')+def add_rpath_stuff(self):+ all = self.to_list(getattr(self, 'use', []))+ while all:+ name = all.pop()+ try:+ tg = self.bld.get_tgen_by_name(name)+ except:+ continue+ self.env.append_value('RPATH', tg.link_task.outputs[0].parent.abspath())+ all.extend(self.to_list(getattr(tg, 'use', [])))+new file mode 100644@@ -0,0 +1,98 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy 2011++import os, shutil, re+from waflib import Options, Build, Logs++"""+Apply a least recently used policy to the Waf cache.++For performance reasons, it is called after the build is complete.++We assume that the the folders are written atomically++Do export WAFCACHE=/tmp/foo_xyz where xyz represents the cache size in bytes+If missing, the default cache size will be set to 10GB+"""++re_num = re.compile('[a-zA-Z_-]+(\d+)')++CACHESIZE = 10*1024*1024*1024 # in bytes+CLEANRATIO = 0.8+DIRSIZE = 4096++def compile(self):+ if Options.cache_global and not Options.options.nocache:+ try:+ os.makedirs(Options.cache_global)+ except:+ pass++ try:+ self.raw_compile()+ finally:+ if Options.cache_global and not Options.options.nocache:+ self.sweep()++def sweep(self):+ global CACHESIZE+ CACHEDIR = Options.cache_global++ # get the cache max size from the WAFCACHE filename+ re_num = re.compile('[a-zA-Z_]+(\d+)')+ val = re_num.sub('\\1', os.path.basename(Options.cache_global))+ try:+ CACHESIZE = int(val)+ except:+ pass++ # map folder names to timestamps+ flist = {}+ for x in os.listdir(CACHEDIR):+ j = os.path.join(CACHEDIR, x)+ if os.path.isdir(j) and len(x) == 64: # dir names are md5 hexdigests+ flist[x] = [os.stat(j).st_mtime, 0]++ for (x, v) in flist.items():+ cnt = DIRSIZE # each entry takes 4kB+ d = os.path.join(CACHEDIR, x)+ for k in os.listdir(d):+ cnt += os.stat(os.path.join(d, k)).st_size+ flist[x][1] = cnt++ total = sum([x[1] for x in flist.values()])+ Logs.debug('lru: Cache size is %r' % total)++ if total >= CACHESIZE:+ Logs.debug('lru: Trimming the cache since %r > %r' % (total, CACHESIZE))++ # make a list to sort the folders by timestamp+ lst = [(p, v[0], v[1]) for (p, v) in flist.items()]+ lst.sort(key=lambda x: x[1]) # sort by timestamp+ lst.reverse()++ while total >= CACHESIZE * CLEANRATIO:+ (k, t, s) = lst.pop()+ p = os.path.join(CACHEDIR, k)+ v = p + '.del'+ try:+ os.rename(p, v)+ except:+ # someone already did it+ pass+ else:+ try:+ shutil.rmtree(v)+ except:+ # this should not happen, but who knows?+ Logs.warn('If you ever see this message, report it (%r)' % v)+ total -= s+ del flist[k]++ Logs.debug('lru: Total at the end %r' % total)++Build.BuildContext.raw_compile = Build.BuildContext.compile+Build.BuildContext.compile = compile+Build.BuildContext.sweep = sweep+new file mode 100644@@ -0,0 +1,142 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2011 (ita)++"""+A make-like way of executing the build, following the relationships between inputs/outputs++This algorithm will lead to slower builds, will not be as flexible as "waf build", but+it might be useful for building data files (?)++It is likely to break in the following cases:+- files are created dynamically (no inputs or outputs)+- headers+- building two files from different groups+"""++import re+from waflib import Options, Task, Logs+from waflib.Build import BuildContext++class MakeContext(BuildContext):+ '''executes tasks in a step-by-step manner, following dependencies between inputs/outputs'''+ cmd = 'make'+ fun = 'build'++ def __init__(self, **kw):+ super(MakeContext, self).__init__(**kw)+ self.files = Options.options.files++ def get_build_iterator(self):+ if not self.files:+ while 1:+ yield super(MakeContext, self).get_build_iterator()++ for g in self.groups:+ for tg in g:+ try:+ f = tg.post+ except AttributeError:+ pass+ else:+ f()++ provides = {}+ uses = {}+ all_tasks = []+ tasks = []+ for pat in self.files.split(','):+ matcher = self.get_matcher(pat)+ for tg in g:+ if isinstance(tg, Task.TaskBase):+ lst = [tg]+ else:+ lst = tg.tasks+ for tsk in lst:+ all_tasks.append(tsk)++ do_exec = False+ for node in getattr(tsk, 'inputs', []):+ try:+ uses[node].append(tsk)+ except:+ uses[node] = [tsk]++ if matcher(node, output=False):+ do_exec = True+ break++ for node in getattr(tsk, 'outputs', []):+ try:+ provides[node].append(tsk)+ except:+ provides[node] = [tsk]++ if matcher(node, output=True):+ do_exec = True+ break+ if do_exec:+ tasks.append(tsk)++ # so we have the tasks that we need to process, the list of all tasks,+ # the map of the tasks providing nodes, and the map of tasks using nodes++ if not tasks:+ # if there are no tasks matching, return everything in the current group+ result = all_tasks+ else:+ # this is like a big filter...+ result = set([])+ seen = set([])+ cur = set(tasks)+ while cur:+ result |= cur+ tosee = set([])+ for tsk in cur:+ for node in getattr(tsk, 'inputs', []):+ if node in seen:+ continue+ seen.add(node)+ tosee |= set(provides.get(node, []))+ cur = tosee+ result = list(result)++ Task.set_file_constraints(result)+ Task.set_precedence_constraints(result)+ yield result++ while 1:+ yield []++ def get_matcher(self, pat):+ # this returns a function+ inn = True+ out = True+ if pat.startswith('in:'):+ out = False+ pat = pat.replace('in:', '')+ elif pat.startswith('out:'):+ inn = False+ pat = pat.replace('out:', '')++ anode = self.root.find_node(pat)+ pattern = None+ if not anode:+ if not pat.startswith('^'):+ pat = '^.+?%s' % pat+ if not pat.endswith('$'):+ pat = '%s$' % pat+ pattern = re.compile(pat)++ def match(node, output):+ if output == True and not out:+ return False+ if output == False and not inn:+ return False++ if anode:+ return anode == node+ else:+ return pattern.match(node.abspath())+ return match+new file mode 100644@@ -0,0 +1,70 @@+#! /usr/bin/env python+# encoding: utf-8++"""+This module assumes that only one build context is running at a given time, which+is not the case if you want to execute configuration tests in parallel.++Store some values on the buildcontext mapping file paths to+stat values and md5 values (timestamp + md5)+this way the md5 hashes are computed only when timestamp change (can be faster)+There is usually little or no gain from enabling this, but it can be used to enable+the second level cache with timestamps (WAFCACHE)++You may have to run distclean or to remove the build directory before enabling/disabling+this hashing scheme+"""++import os, stat+try: import cPickle+except: import pickle as cPickle+from waflib import Utils, Build, Context++STRONGEST = True++try:+ Build.BuildContext.store_real+except AttributeError:++ Context.DBFILE += '_md5tstamp'++ Build.hashes_md5_tstamp = {}+ Build.SAVED_ATTRS.append('hashes_md5_tstamp')+ def store(self):+ # save the hash cache as part of the default pickle file+ self.hashes_md5_tstamp = Build.hashes_md5_tstamp+ self.store_real()+ Build.BuildContext.store_real = Build.BuildContext.store+ Build.BuildContext.store = store++ def restore(self):+ # we need a module variable for h_file below+ self.restore_real()+ try:+ Build.hashes_md5_tstamp = self.hashes_md5_tstamp or {}+ except Exception as e:+ Build.hashes_md5_tstamp = {}+ Build.BuildContext.restore_real = Build.BuildContext.restore+ Build.BuildContext.restore = restore++ def h_file(filename):+ st = os.stat(filename)+ if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')++ if filename in Build.hashes_md5_tstamp:+ if Build.hashes_md5_tstamp[filename][0] == str(st.st_mtime):+ return Build.hashes_md5_tstamp[filename][1]+ if STRONGEST:+ ret = Utils.h_file_no_md5(filename)+ Build.hashes_md5_tstamp[filename] = (str(st.st_mtime), ret)+ return ret+ else:+ m = Utils.md5()+ m.update(str(st.st_mtime))+ m.update(str(st.st_size))+ m.update(filename)+ Build.hashes_md5_tstamp[filename] = (str(st.st_mtime), m.digest())+ return m.digest()+ Utils.h_file_no_md5 = Utils.h_file+ Utils.h_file = h_file+new file mode 100644@@ -0,0 +1,85 @@+#!/usr/bin/env python+# Issue 1185 ultrix gmail com++"""+Microsoft Interface Definition Language support. Given ComObject.idl, this tool+will generate ComObject.tlb ComObject_i.h ComObject_i.c ComObject_p.c and dlldata.c++To declare targets using midl::++ def configure(conf):+ conf.load('msvc')+ conf.load('midl')++ def build(bld):+ bld(+ features='c cshlib',+ # Note: ComObject_i.c is generated from ComObject.idl+ source = 'main.c ComObject.idl ComObject_i.c',+ target = 'ComObject.dll')+"""++from waflib import Task, Utils+from waflib.TaskGen import feature, before_method+import os++def configure(conf):+ conf.find_program(['midl'], var='MIDL')++ conf.env.MIDLFLAGS = [+ '/nologo',+ '/D',+ '_DEBUG',+ '/W1',+ '/char',+ 'signed',+ '/Oicf',+ ]++@feature('c', 'cxx')+@before_method('process_source')+def idl_file(self):+ # Do this before process_source so that the generated header can be resolved+ # when scanning source dependencies.+ idl_nodes = []+ src_nodes = []+ for node in Utils.to_list(self.source):+ if str(node).endswith('.idl'):+ idl_nodes.append(node)+ else:+ src_nodes.append(node)++ for node in self.to_nodes(idl_nodes):+ t = node.change_ext('.tlb')+ h = node.change_ext('_i.h')+ c = node.change_ext('_i.c')+ p = node.change_ext('_p.c')+ d = node.parent.find_or_declare('dlldata.c')+ tsk = self.create_task('midl', node, [t, h, c, p, d])++ self.source = src_nodes++class midl(Task.Task):+ """+ Compile idl files+ """+ color = 'YELLOW'+ run_str = '${MIDL} ${MIDLFLAGS} ${CPPPATH_ST:INCLUDES} /tlb ${TGT[0].bldpath()} /header ${TGT[1].bldpath()} /iid ${TGT[2].bldpath()} /proxy ${TGT[3].bldpath()} /dlldata ${TGT[4].bldpath()} ${SRC}'+ before = ['winrc']++ def exec_command(self, *k, **kw):+ if self.env['PATH']:+ env = self.env.env or dict(os.environ)+ env.update(PATH = ';'.join(self.env['PATH']))+ kw['env'] = env+ + bld = self.generator.bld+ + try:+ if not kw.get('cwd', None):+ kw['cwd'] = bld.cwd+ except AttributeError:+ bld.cwd = kw['cwd'] = bld.variant_dir+ + return bld.exec_command(k[0], **kw)+new file mode 100644@@ -0,0 +1,416 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"""+This tool is totally deprecated++Try using:+ .pc.in files for .pc files+ the feature intltool_in - see demos/intltool+ make-like rules+"""++import shutil, re, os+from waflib import TaskGen, Node, Task, Utils, Build, Errors+from waflib.TaskGen import feature, after_method, before_method+from waflib.Logs import debug++def copy_attrs(orig, dest, names, only_if_set=False):+ """+ copy class attributes from an object to another+ """+ for a in Utils.to_list(names):+ u = getattr(orig, a, ())+ if u or not only_if_set:+ setattr(dest, a, u)++def copy_func(tsk):+ "Make a file copy. This might be used to make other kinds of file processing (even calling a compiler is possible)"+ env = tsk.env+ infile = tsk.inputs[0].abspath()+ outfile = tsk.outputs[0].abspath()+ try:+ shutil.copy2(infile, outfile)+ except (OSError, IOError):+ return 1+ else:+ if tsk.chmod: os.chmod(outfile, tsk.chmod)+ return 0++def action_process_file_func(tsk):+ "Ask the function attached to the task to process it"+ if not tsk.fun: raise Errors.WafError('task must have a function attached to it for copy_func to work!')+ return tsk.fun(tsk)++@feature('cmd')+def apply_cmd(self):+ "call a command everytime"+ if not self.fun: raise Errors.WafError('cmdobj needs a function!')+ tsk = Task.TaskBase()+ tsk.fun = self.fun+ tsk.env = self.env+ self.tasks.append(tsk)+ tsk.install_path = self.install_path++@feature('copy')+@before_method('process_source')+def apply_copy(self):+ Utils.def_attrs(self, fun=copy_func)+ self.default_install_path = 0++ lst = self.to_list(self.source)+ self.meths.remove('process_source')++ for filename in lst:+ node = self.path.find_resource(filename)+ if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)++ target = self.target+ if not target or len(lst)>1: target = node.name++ # TODO the file path may be incorrect+ newnode = self.path.find_or_declare(target)++ tsk = self.create_task('copy', node, newnode)+ tsk.fun = self.fun+ tsk.chmod = getattr(self, 'chmod', Utils.O644)++ if not tsk.env:+ tsk.debug()+ raise Errors.WafError('task without an environment')++def subst_func(tsk):+ "Substitutes variables in a .in file"++ m4_re = re.compile('@(\w+)@', re.M)++ code = tsk.inputs[0].read() #Utils.readf(infile)++ # replace all % by %% to prevent errors by % signs in the input file while string formatting+ code = code.replace('%', '%%')++ s = m4_re.sub(r'%(\1)s', code)++ env = tsk.env+ di = getattr(tsk, 'dict', {}) or getattr(tsk.generator, 'dict', {})+ if not di:+ names = m4_re.findall(code)+ for i in names:+ di[i] = env.get_flat(i) or env.get_flat(i.upper())++ tsk.outputs[0].write(s % di)++@feature('subst')+@before_method('process_source')+def apply_subst(self):+ Utils.def_attrs(self, fun=subst_func)+ lst = self.to_list(self.source)+ self.meths.remove('process_source')++ self.dict = getattr(self, 'dict', {})++ for filename in lst:+ node = self.path.find_resource(filename)+ if not node: raise Errors.WafError('cannot find input file %s for processing' % filename)++ if self.target:+ newnode = self.path.find_or_declare(self.target)+ else:+ newnode = node.change_ext('')++ try:+ self.dict = self.dict.get_merged_dict()+ except AttributeError:+ pass++ if self.dict and not self.env['DICT_HASH']:+ self.env = self.env.derive()+ keys = list(self.dict.keys())+ keys.sort()+ lst = [self.dict[x] for x in keys]+ self.env['DICT_HASH'] = str(Utils.h_list(lst))++ tsk = self.create_task('copy', node, newnode)+ tsk.fun = self.fun+ tsk.dict = self.dict+ tsk.dep_vars = ['DICT_HASH']+ tsk.chmod = getattr(self, 'chmod', Utils.O644)++ if not tsk.env:+ tsk.debug()+ raise Errors.WafError('task without an environment')++####################+## command-output ####+####################++class cmd_arg(object):+ """command-output arguments for representing files or folders"""+ def __init__(self, name, template='%s'):+ self.name = name+ self.template = template+ self.node = None++class input_file(cmd_arg):+ def find_node(self, base_path):+ assert isinstance(base_path, Node.Node)+ self.node = base_path.find_resource(self.name)+ if self.node is None:+ raise Errors.WafError("Input file %s not found in " % (self.name, base_path))++ def get_path(self, env, absolute):+ if absolute:+ return self.template % self.node.abspath()+ else:+ return self.template % self.node.srcpath()++class output_file(cmd_arg):+ def find_node(self, base_path):+ assert isinstance(base_path, Node.Node)+ self.node = base_path.find_or_declare(self.name)+ if self.node is None:+ raise Errors.WafError("Output file %s not found in " % (self.name, base_path))++ def get_path(self, env, absolute):+ if absolute:+ return self.template % self.node.abspath()+ else:+ return self.template % self.node.bldpath()++class cmd_dir_arg(cmd_arg):+ def find_node(self, base_path):+ assert isinstance(base_path, Node.Node)+ self.node = base_path.find_dir(self.name)+ if self.node is None:+ raise Errors.WafError("Directory %s not found in " % (self.name, base_path))++class input_dir(cmd_dir_arg):+ def get_path(self, dummy_env, dummy_absolute):+ return self.template % self.node.abspath()++class output_dir(cmd_dir_arg):+ def get_path(self, env, dummy_absolute):+ return self.template % self.node.abspath()+++class command_output(Task.Task):+ color = "BLUE"+ def __init__(self, env, command, command_node, command_args, stdin, stdout, cwd, os_env, stderr):+ Task.Task.__init__(self, env=env)+ assert isinstance(command, (str, Node.Node))+ self.command = command+ self.command_args = command_args+ self.stdin = stdin+ self.stdout = stdout+ self.cwd = cwd+ self.os_env = os_env+ self.stderr = stderr++ if command_node is not None: self.dep_nodes = [command_node]+ self.dep_vars = [] # additional environment variables to look++ def run(self):+ task = self+ #assert len(task.inputs) > 0++ def input_path(node, template):+ if task.cwd is None:+ return template % node.bldpath()+ else:+ return template % node.abspath()+ def output_path(node, template):+ fun = node.abspath+ if task.cwd is None: fun = node.bldpath+ return template % fun()++ if isinstance(task.command, Node.Node):+ argv = [input_path(task.command, '%s')]+ else:+ argv = [task.command]++ for arg in task.command_args:+ if isinstance(arg, str):+ argv.append(arg)+ else:+ assert isinstance(arg, cmd_arg)+ argv.append(arg.get_path(task.env, (task.cwd is not None)))++ if task.stdin:+ stdin = open(input_path(task.stdin, '%s'))+ else:+ stdin = None++ if task.stdout:+ stdout = open(output_path(task.stdout, '%s'), "w")+ else:+ stdout = None++ if task.stderr:+ stderr = open(output_path(task.stderr, '%s'), "w")+ else:+ stderr = None++ if task.cwd is None:+ cwd = ('None (actually %r)' % os.getcwd())+ else:+ cwd = repr(task.cwd)+ debug("command-output: cwd=%s, stdin=%r, stdout=%r, argv=%r" %+ (cwd, stdin, stdout, argv))++ if task.os_env is None:+ os_env = os.environ+ else:+ os_env = task.os_env+ command = Utils.subprocess.Popen(argv, stdin=stdin, stdout=stdout, stderr=stderr, cwd=task.cwd, env=os_env)+ return command.wait()++@feature('command-output')+def init_cmd_output(self):+ Utils.def_attrs(self,+ stdin = None,+ stdout = None,+ stderr = None,+ # the command to execute+ command = None,++ # whether it is an external command; otherwise it is assumed+ # to be an executable binary or script that lives in the+ # source or build tree.+ command_is_external = False,++ # extra parameters (argv) to pass to the command (excluding+ # the command itself)+ argv = [],++ # dependencies to other objects -> this is probably not what you want (ita)+ # values must be 'task_gen' instances (not names!)+ dependencies = [],++ # dependencies on env variable contents+ dep_vars = [],++ # input files that are implicit, i.e. they are not+ # stdin, nor are they mentioned explicitly in argv+ hidden_inputs = [],++ # output files that are implicit, i.e. they are not+ # stdout, nor are they mentioned explicitly in argv+ hidden_outputs = [],++ # change the subprocess to this cwd (must use obj.input_dir() or output_dir() here)+ cwd = None,++ # OS environment variables to pass to the subprocess+ # if None, use the default environment variables unchanged+ os_env = None)++@feature('command-output')+@after_method('init_cmd_output')+def apply_cmd_output(self):+ if self.command is None:+ raise Errors.WafError("command-output missing command")+ if self.command_is_external:+ cmd = self.command+ cmd_node = None+ else:+ cmd_node = self.path.find_resource(self.command)+ assert cmd_node is not None, ('''Could not find command '%s' in source tree.+Hint: if this is an external command,+use command_is_external=True''') % (self.command,)+ cmd = cmd_node++ if self.cwd is None:+ cwd = None+ else:+ assert isinstance(cwd, CmdDirArg)+ self.cwd.find_node(self.path)++ args = []+ inputs = []+ outputs = []++ for arg in self.argv:+ if isinstance(arg, cmd_arg):+ arg.find_node(self.path)+ if isinstance(arg, input_file):+ inputs.append(arg.node)+ if isinstance(arg, output_file):+ outputs.append(arg.node)++ if self.stdout is None:+ stdout = None+ else:+ assert isinstance(self.stdout, str)+ stdout = self.path.find_or_declare(self.stdout)+ if stdout is None:+ raise Errors.WafError("File %s not found" % (self.stdout,))+ outputs.append(stdout)++ if self.stderr is None:+ stderr = None+ else:+ assert isinstance(self.stderr, str)+ stderr = self.path.find_or_declare(self.stderr)+ if stderr is None:+ raise Errors.WafError("File %s not found" % (self.stderr,))+ outputs.append(stderr)++ if self.stdin is None:+ stdin = None+ else:+ assert isinstance(self.stdin, str)+ stdin = self.path.find_resource(self.stdin)+ if stdin is None:+ raise Errors.WafError("File %s not found" % (self.stdin,))+ inputs.append(stdin)++ for hidden_input in self.to_list(self.hidden_inputs):+ node = self.path.find_resource(hidden_input)+ if node is None:+ raise Errors.WafError("File %s not found in dir %s" % (hidden_input, self.path))+ inputs.append(node)++ for hidden_output in self.to_list(self.hidden_outputs):+ node = self.path.find_or_declare(hidden_output)+ if node is None:+ raise Errors.WafError("File %s not found in dir %s" % (hidden_output, self.path))+ outputs.append(node)++ if not (inputs or getattr(self, 'no_inputs', None)):+ raise Errors.WafError('command-output objects must have at least one input file or give self.no_inputs')+ if not (outputs or getattr(self, 'no_outputs', None)):+ raise Errors.WafError('command-output objects must have at least one output file or give self.no_outputs')++ cwd = self.bld.variant_dir+ task = command_output(self.env, cmd, cmd_node, self.argv, stdin, stdout, cwd, self.os_env, stderr)+ task.generator = self+ copy_attrs(self, task, 'before after ext_in ext_out', only_if_set=True)+ self.tasks.append(task)++ task.inputs = inputs+ task.outputs = outputs+ task.dep_vars = self.to_list(self.dep_vars)++ for dep in self.dependencies:+ assert dep is not self+ dep.post()+ for dep_task in dep.tasks:+ task.set_run_after(dep_task)++ if not task.inputs:+ # the case for svnversion, always run, and update the output nodes+ task.runnable_status = type(Task.TaskBase.run)(runnable_status, task, task.__class__) # always run+ task.post_run = type(Task.TaskBase.run)(post_run, task, task.__class__)++ # TODO the case with no outputs?++def post_run(self):+ for x in self.outputs:+ x.sig = Utils.h_file(x.abspath())++def runnable_status(self):+ return self.RUN_ME++Task.task_factory('copy', vars=[], func=action_process_file_func)+new file mode 100644@@ -0,0 +1,1021 @@+#! /usr/bin/env python+# encoding: utf-8+# Avalanche Studios 2009-2011+# Thomas Nagy 2011++"""+Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++3. The name of the author may not be used to endorse or promote products+ derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.+"""++"""+To add this tool to your project:+def options(conf):+ opt.load('msvs')++It can be a good idea to add the sync_exec tool too.++To generate solution files:+$ waf configure msvs++To customize the outputs, provide subclasses in your wscript files:++from waflib.extras import msvs+class vsnode_target(msvs.vsnode_target):+ def get_build_command(self, props):+ # likely to be required+ return "waf.bat build"+ def collect_source(self):+ # likely to be required+ ...+class msvs_bar(msvs.msvs_generator):+ def init(self):+ msvs.msvs_generator.init(self)+ self.vsnode_target = vsnode_target++The msvs class re-uses the same build() function for reading the targets (task generators),+you may therefore specify msvs settings on the context object:++def build(bld):+ bld.solution_name = 'foo.sln'+ bld.waf_command = 'waf.bat'+ bld.projects_dir = bld.srcnode.make_node('.depproj')+ bld.projects_dir.mkdir()++For visual studio 2008, the command is called 'msvs2008', and the classes+such as vsnode_target are wrapped by a decorator class 'wrap_2008' to+provide special functionality.++ASSUMPTIONS:+* a project can be either a directory or a target, vcxproj files are written only for targets that have source files+* each project is a vcxproj file, therefore the project uuid needs only to be a hash of the absolute path+"""++import os, re, sys+import uuid # requires python 2.5+from waflib.Build import BuildContext+from waflib import Utils, TaskGen, Logs, Task, Context, Node, Options++HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)'++PROJECT_TEMPLATE = r'''<?xml version="1.0" encoding="UTF-8"?>+<Project DefaultTargets="Build" ToolsVersion="4.0"+ xmlns="http://schemas.microsoft.com/developer/msbuild/2003">++ <ItemGroup Label="ProjectConfigurations">+ ${for b in project.build_properties}+ <ProjectConfiguration Include="${b.configuration}|${b.platform}">+ <Configuration>${b.configuration}</Configuration>+ <Platform>${b.platform}</Platform>+ </ProjectConfiguration>+ ${endfor}+ </ItemGroup>++ <PropertyGroup Label="Globals">+ <ProjectGuid>{${project.uuid}}</ProjectGuid>+ <Keyword>MakeFileProj</Keyword>+ <ProjectName>${project.name}</ProjectName>+ </PropertyGroup>+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />++ ${for b in project.build_properties}+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'" Label="Configuration">+ <ConfigurationType>Makefile</ConfigurationType>+ <OutDir>${b.outdir}</OutDir>+ </PropertyGroup>+ ${endfor}++ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />+ <ImportGroup Label="ExtensionSettings">+ </ImportGroup>++ ${for b in project.build_properties}+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />+ </ImportGroup>+ ${endfor}++ ${for b in project.build_properties}+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">+ <NMakeBuildCommandLine>${xml:project.get_build_command(b)}</NMakeBuildCommandLine>+ <NMakeReBuildCommandLine>${xml:project.get_rebuild_command(b)}</NMakeReBuildCommandLine>+ <NMakeCleanCommandLine>${xml:project.get_clean_command(b)}</NMakeCleanCommandLine>+ <NMakeIncludeSearchPath>${xml:b.includes_search_path}</NMakeIncludeSearchPath>+ <NMakePreprocessorDefinitions>${xml:b.preprocessor_definitions};$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>+ <IncludePath>${xml:b.includes_search_path}</IncludePath>+ <ExecutablePath>$(ExecutablePath)</ExecutablePath>++ ${if getattr(b, 'output_file', None)}+ <NMakeOutput>${xml:b.output_file}</NMakeOutput>+ ${endif}+ ${if getattr(b, 'deploy_dir', None)}+ <RemoteRoot>${xml:b.deploy_dir}</RemoteRoot>+ ${endif}+ </PropertyGroup>+ ${endfor}++ ${for b in project.build_properties}+ ${if getattr(b, 'deploy_dir', None)}+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='${b.configuration}|${b.platform}'">+ <Deploy>+ <DeploymentType>CopyToHardDrive</DeploymentType>+ </Deploy>+ </ItemDefinitionGroup>+ ${endif}+ ${endfor}++ <ItemGroup>+ ${for x in project.source}+ <${project.get_key(x)} Include='${x.abspath()}' />+ ${endfor}+ </ItemGroup>+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />+ <ImportGroup Label="ExtensionTargets">+ </ImportGroup>+</Project>+'''++FILTER_TEMPLATE = '''<?xml version="1.0" encoding="UTF-8"?>+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">+ <ItemGroup>+ ${for x in project.source}+ <${project.get_key(x)} Include="${x.abspath()}">+ <Filter>${project.get_filter_name(x.parent)}</Filter>+ </${project.get_key(x)}>+ ${endfor}+ </ItemGroup>+ <ItemGroup>+ ${for x in project.dirs()}+ <Filter Include="${project.get_filter_name(x)}">+ <UniqueIdentifier>{${project.make_uuid(x.abspath())}}</UniqueIdentifier>+ </Filter>+ ${endfor}+ </ItemGroup>+</Project>+'''++PROJECT_2008_TEMPLATE = r'''<?xml version="1.0" encoding="UTF-8"?>+<VisualStudioProject ProjectType="Visual C++" Version="9,00"+ Name="${xml: project.name}" ProjectGUID="{${project.uuid}}"+ Keyword="MakeFileProj"+ TargetFrameworkVersion="196613">+ <Platforms>+ ${if project.build_properties}+ ${for b in project.build_properties}+ <Platform Name="${xml: b.platform}" />+ ${endfor}+ ${else}+ <Platform Name="Win32" />+ ${endif}+ </Platforms>+ <ToolFiles>+ </ToolFiles>+ <Configurations>+ ${if project.build_properties}+ ${for b in project.build_properties}+ <Configuration+ Name="${xml: b.configuration}|${xml: b.platform}"+ IntermediateDirectory="$ConfigurationName"+ OutputDirectory="${xml: b.outdir}"+ ConfigurationType="0">+ <Tool+ Name="VCNMakeTool"+ BuildCommandLine="${xml: project.get_build_command(b)}"+ ReBuildCommandLine="${xml: project.get_rebuild_command(b)}"+ CleanCommandLine="${xml: project.get_clean_command(b)}"+ ${if getattr(b, 'output_file', None)}+ Output="${xml: b.output_file}"+ ${endif}+ PreprocessorDefinitions="${xml: b.preprocessor_definitions}"+ IncludeSearchPath="${xml: b.includes_search_path}"+ ForcedIncludes=""+ ForcedUsingAssemblies=""+ AssemblySearchPath=""+ CompileAsManaged=""+ />+ </Configuration>+ ${endfor}+ ${else}+ <Configuration Name="Release|Win32" >+ </Configuration>+ ${endif}+ </Configurations>+ <References>+ </References>+ <Files>+${project.display_filter()}+ </Files>+</VisualStudioProject>+'''++SOLUTION_TEMPLATE = '''Microsoft Visual Studio Solution File, Format Version ${project.numver}+# Visual Studio ${project.vsver}+${for p in project.all_projects}+Project("{${p.ptype()}}") = "${p.name}", "${p.title}", "{${p.uuid}}"+EndProject${endfor}+Global+ GlobalSection(SolutionConfigurationPlatforms) = preSolution+ ${if project.all_projects}+ ${for (configuration, platform) in project.all_projects[0].ctx.project_configurations()}+ ${configuration}|${platform} = ${configuration}|${platform}+ ${endfor}+ ${endif}+ EndGlobalSection+ GlobalSection(ProjectConfigurationPlatforms) = postSolution+ ${for p in project.all_projects}+ ${if hasattr(p, 'source')}+ ${for b in p.build_properties}+ {${p.uuid}}.${b.configuration}|${b.platform}.ActiveCfg = ${b.configuration}|${b.platform}+ ${if getattr(p, 'is_active', None)}+ {${p.uuid}}.${b.configuration}|${b.platform}.Build.0 = ${b.configuration}|${b.platform}+ ${endif}+ ${endfor}+ ${endif}+ ${endfor}+ EndGlobalSection+ GlobalSection(SolutionProperties) = preSolution+ HideSolutionNode = FALSE+ EndGlobalSection+ GlobalSection(NestedProjects) = preSolution+ ${for p in project.all_projects}+ ${if p.parent}+ {${p.uuid}} = {${p.parent.uuid}}+ ${endif}+ ${endfor}+ EndGlobalSection+EndGlobal+'''++COMPILE_TEMPLATE = '''def f(project):+ lst = []+ def xml_escape(value):+ return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">")++ %s++ #f = open('cmd.txt', 'w')+ #f.write(str(lst))+ #f.close()+ return ''.join(lst)+'''+reg_act = re.compile(r"(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<code>[^}]*?)\})", re.M)+def compile_template(line):+ """+ Compile a template expression into a python function (like jsps, but way shorter)+ """+ extr = []+ def repl(match):+ g = match.group+ if g('dollar'): return "$"+ elif g('backslash'):+ return "\\"+ elif g('subst'):+ extr.append(g('code'))+ return "<<|@|>>"+ return None++ line2 = reg_act.sub(repl, line)+ params = line2.split('<<|@|>>')+ assert(extr)+++ indent = 0+ buf = []+ app = buf.append++ def app(txt):+ buf.append(indent * '\t' + txt)++ for x in range(len(extr)):+ if params[x]:+ app("lst.append(%r)" % params[x])++ f = extr[x]+ if f.startswith('if') or f.startswith('for'):+ app(f + ':')+ indent += 1+ elif f.startswith('py:'):+ app(f[3:])+ elif f.startswith('endif') or f.startswith('endfor'):+ indent -= 1+ elif f.startswith('else') or f.startswith('elif'):+ indent -= 1+ app(f + ':')+ indent += 1+ elif f.startswith('xml:'):+ app('lst.append(xml_escape(%s))' % f[4:])+ else:+ #app('lst.append((%s) or "cannot find %s")' % (f, f))+ app('lst.append(%s)' % f)++ if extr:+ if params[-1]:+ app("lst.append(%r)" % params[-1])++ fun = COMPILE_TEMPLATE % "\n\t".join(buf)+ #print(fun)+ return Task.funex(fun)+++re_blank = re.compile('(\n|\r|\\s)*\n', re.M)+def rm_blank_lines(txt):+ txt = re_blank.sub('\r\n', txt)+ return txt++BOM = '\xef\xbb\xbf'+try:+ BOM = bytes(BOM, 'iso8859-1') # python 3+except:+ pass++def stealth_write(self, data, flags='wb'):+ try:+ x = unicode+ except:+ data = data.encode('utf-8') # python 3+ else:+ data = data.decode(sys.getfilesystemencoding(), 'replace')+ data = data.encode('utf-8')++ if self.name.endswith('.vcproj') or self.name.endswith('.vcxproj'):+ data = BOM + data++ try:+ txt = self.read(flags='rb')+ if txt != data:+ raise ValueError('must write')+ except (IOError, ValueError):+ self.write(data, flags=flags)+ else:+ Logs.debug('msvs: skipping %s' % self.abspath())+Node.Node.stealth_write = stealth_write++re_quote = re.compile("[^a-zA-Z0-9-]")+def quote(s):+ return re_quote.sub("_", s)++def xml_escape(value):+ return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">")++def make_uuid(v, prefix = None):+ """+ simple utility function+ """+ if isinstance(v, dict):+ keys = list(v.keys())+ keys.sort()+ tmp = str([(k, v[k]) for k in keys])+ else:+ tmp = str(v)+ d = Utils.md5(tmp.encode()).hexdigest().upper()+ if prefix:+ d = '%s%s' % (prefix, d[8:])+ gid = uuid.UUID(d, version = 4)+ return str(gid).upper()++def diff(node, fromnode):+ # difference between two nodes, but with "(..)" instead of ".."+ c1 = node+ c2 = fromnode++ c1h = c1.height()+ c2h = c2.height()++ lst = []+ up = 0++ while c1h > c2h:+ lst.append(c1.name)+ c1 = c1.parent+ c1h -= 1++ while c2h > c1h:+ up += 1+ c2 = c2.parent+ c2h -= 1++ while id(c1) != id(c2):+ lst.append(c1.name)+ up += 1++ c1 = c1.parent+ c2 = c2.parent++ for i in range(up):+ lst.append('(..)')+ lst.reverse()+ return tuple(lst)++class build_property(object):+ pass++class vsnode(object):+ """+ Abstract class representing visual studio elements+ We assume that all visual studio nodes have a uuid and a parent+ """+ def __init__(self, ctx):+ self.ctx = ctx # msvs context+ self.name = '' # string, mandatory+ self.vspath = '' # path in visual studio (name for dirs, absolute path for projects)+ self.uuid = '' # string, mandatory+ self.parent = None # parent node for visual studio nesting++ def get_waf(self):+ """+ Override in subclasses...+ """+ return 'cd /d "%s" & %s' % (self.ctx.srcnode.abspath(), getattr(self.ctx, 'waf_command', 'waf.bat'))++ def ptype(self):+ """+ Return a special uuid for projects written in the solution file+ """+ pass++ def write(self):+ """+ Write the project file, by default, do nothing+ """+ pass++ def make_uuid(self, val):+ """+ Alias for creating uuid values easily (the templates cannot access global variables)+ """+ return make_uuid(val)++class vsnode_vsdir(vsnode):+ """+ Nodes representing visual studio folders (which do not match the filesystem tree!)+ """+ VS_GUID_SOLUTIONFOLDER = "2150E333-8FDC-42A3-9474-1A3956D46DE8"+ def __init__(self, ctx, uuid, name, vspath=''):+ vsnode.__init__(self, ctx)+ self.title = self.name = name+ self.uuid = uuid+ self.vspath = vspath or name++ def ptype(self):+ return self.VS_GUID_SOLUTIONFOLDER++class vsnode_project(vsnode):+ """+ Abstract class representing visual studio project elements+ A project is assumed to be writable, and has a node representing the file to write to+ """+ VS_GUID_VCPROJ = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"+ def ptype(self):+ return self.VS_GUID_VCPROJ++ def __init__(self, ctx, node):+ vsnode.__init__(self, ctx)+ self.path = node+ self.uuid = make_uuid(node.abspath())+ self.name = node.name+ self.title = self.path.abspath()+ self.source = [] # list of node objects+ self.build_properties = [] # list of properties (nmake commands, output dir, etc)++ def dirs(self):+ """+ Get the list of parent folders of the source files (header files included)+ for writing the filters+ """+ lst = []+ def add(x):+ if x.height() > self.tg.path.height() and x not in lst:+ lst.append(x)+ add(x.parent)+ for x in self.source:+ add(x.parent)+ return lst++ def write(self):+ Logs.debug('msvs: creating %r' % self.path)++ # first write the project file+ template1 = compile_template(PROJECT_TEMPLATE)+ proj_str = template1(self)+ proj_str = rm_blank_lines(proj_str)+ self.path.stealth_write(proj_str)++ # then write the filter+ template2 = compile_template(FILTER_TEMPLATE)+ filter_str = template2(self)+ filter_str = rm_blank_lines(filter_str)+ tmp = self.path.parent.make_node(self.path.name + '.filters')+ tmp.stealth_write(filter_str)++ def get_key(self, node):+ """+ required for writing the source files+ """+ name = node.name+ if name.endswith('.cpp') or name.endswith('.c'):+ return 'ClCompile'+ return 'ClInclude'++ def collect_properties(self):+ """+ Returns a list of triplet (configuration, platform, output_directory)+ """+ ret = []+ for c in self.ctx.configurations:+ for p in self.ctx.platforms:+ x = build_property()+ x.outdir = ''++ x.configuration = c+ x.platform = p++ x.preprocessor_definitions = ''+ x.includes_search_path = ''++ # can specify "deploy_dir" too+ ret.append(x)+ self.build_properties = ret++ def get_build_params(self, props):+ opt = '--execsolution=%s' % self.ctx.get_solution_node().abspath()+ return (self.get_waf(), opt)++ def get_build_command(self, props):+ return "%s build %s" % self.get_build_params(props)++ def get_clean_command(self, props):+ return "%s clean %s" % self.get_build_params(props)++ def get_rebuild_command(self, props):+ return "%s clean build %s" % self.get_build_params(props)++ def get_filter_name(self, node):+ lst = diff(node, self.tg.path)+ return '\\'.join(lst) or '.'++class vsnode_alias(vsnode_project):+ def __init__(self, ctx, node, name):+ vsnode_project.__init__(self, ctx, node)+ self.name = name+ self.output_file = ''++class vsnode_build_all(vsnode_alias):+ """+ Fake target used to emulate the behaviour of "make all" (starting one process by target is slow)+ This is the only alias enabled by default+ """+ def __init__(self, ctx, node, name='build_all_projects'):+ vsnode_alias.__init__(self, ctx, node, name)+ self.is_active = True++class vsnode_install_all(vsnode_alias):+ """+ Fake target used to emulate the behaviour of "make install"+ """+ def __init__(self, ctx, node, name='install_all_projects'):+ vsnode_alias.__init__(self, ctx, node, name)++ def get_build_command(self, props):+ return "%s build install %s" % self.get_build_params(props)++ def get_clean_command(self, props):+ return "%s clean %s" % self.get_build_params(props)++ def get_rebuild_command(self, props):+ return "%s clean build install %s" % self.get_build_params(props)++class vsnode_project_view(vsnode_alias):+ """+ Fake target used to emulate a file system view+ """+ def __init__(self, ctx, node, name='project_view'):+ vsnode_alias.__init__(self, ctx, node, name)+ self.tg = self.ctx() # fake one, cannot remove+ self.exclude_files = Node.exclude_regs + '''+waf-1.7.*+waf3-1.7.*/**+.waf-1.7.*+.waf3-1.7.*/**+**/*.sdf+**/*.suo+**/*.ncb+**/%s+ ''' % Options.lockfile++ def collect_source(self):+ # this is likely to be slow+ self.source = self.ctx.srcnode.ant_glob('**', excl=self.exclude_files)++ def get_build_command(self, props):+ params = self.get_build_params(props) + (self.ctx.cmd,)+ return "%s %s %s" % params++ def get_clean_command(self, props):+ return ""++ def get_rebuild_command(self, props):+ return self.get_build_command(props)++class vsnode_target(vsnode_project):+ """+ Visual studio project representing a targets (programs, libraries, etc) and bound+ to a task generator+ """+ def __init__(self, ctx, tg):+ """+ A project is more or less equivalent to a file/folder+ """+ base = getattr(ctx, 'projects_dir', None) or tg.path+ node = base.make_node(quote(tg.name) + ctx.project_extension) # the project file as a Node+ vsnode_project.__init__(self, ctx, node)+ self.name = quote(tg.name)+ self.tg = tg # task generator++ def get_build_params(self, props):+ """+ Override the default to add the target name+ """+ opt = '--execsolution=%s' % self.ctx.get_solution_node().abspath()+ if getattr(self, 'tg', None):+ opt += " --targets=%s" % self.tg.name+ return (self.get_waf(), opt)++ def collect_source(self):+ tg = self.tg+ source_files = tg.to_nodes(getattr(tg, 'source', []))+ include_dirs = Utils.to_list(getattr(tg, 'msvs_includes', []))+ include_files = []+ for x in include_dirs:+ if isinstance(x, str):+ x = tg.path.find_node(x)+ if x:+ lst = [y for y in x.ant_glob(HEADERS_GLOB, flat=False)]+ include_files.extend(lst)++ # remove duplicates+ self.source.extend(list(set(source_files + include_files)))+ self.source.sort(key=lambda x: x.abspath())++ def collect_properties(self):+ """+ Visual studio projects are associated with platforms and configurations (for building especially)+ """+ super(vsnode_target, self).collect_properties()+ for x in self.build_properties:+ x.outdir = self.path.parent.abspath()+ x.preprocessor_definitions = ''+ x.includes_search_path = ''++ try:+ tsk = self.tg.link_task+ except AttributeError:+ pass+ else:+ x.output_file = tsk.outputs[0].abspath()+ x.preprocessor_definitions = ';'.join(tsk.env.DEFINES)+ x.includes_search_path = ';'.join(self.tg.env.INCPATHS)++class msvs_generator(BuildContext):+ '''generates a visual studio 2010 solution'''+ cmd = 'msvs'+ fun = 'build'++ def init(self):+ """+ Some data that needs to be present+ """+ if not getattr(self, 'configurations', None):+ self.configurations = ['Release'] # LocalRelease, RemoteDebug, etc+ if not getattr(self, 'platforms', None):+ self.platforms = ['Win32']+ if not getattr(self, 'all_projects', None):+ self.all_projects = []+ if not getattr(self, 'project_extension', None):+ self.project_extension = '.vcxproj'+ if not getattr(self, 'projects_dir', None):+ self.projects_dir = self.srcnode.make_node('.depproj')+ self.projects_dir.mkdir()++ # bind the classes to the object, so that subclass can provide custom generators+ if not getattr(self, 'vsnode_vsdir', None):+ self.vsnode_vsdir = vsnode_vsdir+ if not getattr(self, 'vsnode_target', None):+ self.vsnode_target = vsnode_target+ if not getattr(self, 'vsnode_build_all', None):+ self.vsnode_build_all = vsnode_build_all+ if not getattr(self, 'vsnode_install_all', None):+ self.vsnode_install_all = vsnode_install_all+ if not getattr(self, 'vsnode_project_view', None):+ self.vsnode_project_view = vsnode_project_view++ self.numver = '11.00'+ self.vsver = '2010'++ def execute(self):+ """+ Entry point+ """+ self.restore()+ if not self.all_envs:+ self.load_envs()+ self.recurse([self.run_dir])++ # user initialization+ self.init()++ # two phases for creating the solution+ self.collect_projects() # add project objects into "self.all_projects"+ self.write_files() # write the corresponding project and solution files++ def collect_projects(self):+ """+ Fill the list self.all_projects with project objects+ Fill the list of build targets+ """+ self.collect_targets()+ self.add_aliases()+ self.collect_dirs()+ default_project = getattr(self, 'default_project', None)+ def sortfun(x):+ if x.name == default_project:+ return ''+ return getattr(x, 'path', None) and x.path.abspath() or x.name+ self.all_projects.sort(key=sortfun)++ def write_files(self):+ """+ Write the project and solution files from the data collected+ so far. It is unlikely that you will want to change this+ """+ for p in self.all_projects:+ p.write()++ # and finally write the solution file+ node = self.get_solution_node()+ node.parent.mkdir()+ Logs.warn('Creating %r' % node)+ template1 = compile_template(SOLUTION_TEMPLATE)+ sln_str = template1(self)+ sln_str = rm_blank_lines(sln_str)+ node.stealth_write(sln_str)++ def get_solution_node(self):+ """+ The solution filename is required when writing the .vcproj files+ return self.solution_node and if it does not exist, make one+ """+ try:+ return self.solution_node+ except:+ pass++ solution_name = getattr(self, 'solution_name', None)+ if not solution_name:+ solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '.sln'+ if os.path.isabs(solution_name):+ self.solution_node = self.root.make_node(solution_name)+ else:+ self.solution_node = self.srcnode.make_node(solution_name)+ return self.solution_node++ def project_configurations(self):+ """+ Helper that returns all the pairs (config,platform)+ """+ ret = []+ for c in self.configurations:+ for p in self.platforms:+ ret.append((c, p))+ return ret++ def collect_targets(self):+ """+ Process the list of task generators+ """+ for g in self.groups:+ for tg in g:+ if not isinstance(tg, TaskGen.task_gen):+ continue++ if not hasattr(tg, 'msvs_includes'):+ tg.msvs_includes = tg.to_list(getattr(tg, 'includes', [])) + tg.to_list(getattr(tg, 'export_includes', []))+ tg.post()+ if not getattr(tg, 'link_task', None):+ continue++ p = self.vsnode_target(self, tg)+ p.collect_source() # delegate this processing+ p.collect_properties()+ self.all_projects.append(p)++ def add_aliases(self):+ """+ Add a specific target that emulates the "make all" necessary for Visual studio when pressing F7+ We also add an alias for "make install" (disabled by default)+ """+ base = getattr(self, 'projects_dir', None) or self.tg.path++ node_project = base.make_node('build_all_projects' + self.project_extension) # Node+ p_build = self.vsnode_build_all(self, node_project)+ p_build.collect_properties()+ self.all_projects.append(p_build)++ node_project = base.make_node('install_all_projects' + self.project_extension) # Node+ p_install = self.vsnode_install_all(self, node_project)+ p_install.collect_properties()+ self.all_projects.append(p_install)++ node_project = base.make_node('project_view' + self.project_extension) # Node+ p_view = self.vsnode_project_view(self, node_project)+ p_view.collect_source()+ p_view.collect_properties()+ self.all_projects.append(p_view)++ n = self.vsnode_vsdir(self, make_uuid(self.srcnode.abspath() + 'build_aliases'), "build_aliases")+ p_build.parent = p_install.parent = p_view.parent = n+ self.all_projects.append(n)++ def collect_dirs(self):+ """+ Create the folder structure in the Visual studio project view+ """+ seen = {}+ def make_parents(proj):+ # look at a project, try to make a parent+ if getattr(proj, 'parent', None):+ # aliases already have parents+ return+ x = proj.iter_path+ if x in seen:+ proj.parent = seen[x]+ return++ # There is not vsnode_vsdir for x.+ # So create a project representing the folder "x"+ n = proj.parent = seen[x] = self.vsnode_vsdir(self, make_uuid(x.abspath()), x.name)+ n.iter_path = x.parent+ self.all_projects.append(n)++ # recurse up to the project directory+ if x.height() > self.srcnode.height() + 1:+ make_parents(n)++ for p in self.all_projects[:]: # iterate over a copy of all projects+ if not getattr(p, 'tg', None):+ # but only projects that have a task generator+ continue++ # make a folder for each task generator+ p.iter_path = p.tg.path+ make_parents(p)++def wrap_2008(cls):+ class dec(cls):+ def __init__(self, *k, **kw):+ cls.__init__(self, *k, **kw)+ self.project_template = PROJECT_2008_TEMPLATE++ def display_filter(self):++ root = build_property()+ root.subfilters = []+ root.sourcefiles = []+ root.source = []+ root.name = ''++ @Utils.run_once+ def add_path(lst):+ if not lst:+ return root+ child = build_property()+ child.subfilters = []+ child.sourcefiles = []+ child.source = []+ child.name = lst[-1]++ par = add_path(lst[:-1])+ par.subfilters.append(child)+ return child++ for x in self.source:+ # this crap is for enabling subclasses to override get_filter_name+ tmp = self.get_filter_name(x.parent)+ tmp = tmp != '.' and tuple(tmp.split('\\')) or ()+ par = add_path(tmp)+ par.source.append(x)++ def display(n):+ buf = []+ for x in n.source:+ buf.append('<File RelativePath="%s" FileType="%s"/>\n' % (xml_escape(x.abspath()), self.get_key(x)))+ for x in n.subfilters:+ buf.append('<Filter Name="%s">' % xml_escape(x.name))+ buf.append(display(x))+ buf.append('</Filter>')+ return '\n'.join(buf)++ return display(root)++ def get_key(self, node):+ """+ If you do not want to let visual studio use the default file extensions,+ override this method to return a value:+ 0: C/C++ Code, 1: C++ Class, 2: C++ Header File, 3: C++ Form,+ 4: C++ Control, 5: Text File, 6: DEF File, 7: IDL File,+ 8: Makefile, 9: RGS File, 10: RC File, 11: RES File, 12: XSD File,+ 13: XML File, 14: HTML File, 15: CSS File, 16: Bitmap, 17: Icon,+ 18: Resx File, 19: BSC File, 20: XSX File, 21: C++ Web Service,+ 22: ASAX File, 23: Asp Page, 24: Document, 25: Discovery File,+ 26: C# File, 27: eFileTypeClassDiagram, 28: MHTML Document,+ 29: Property Sheet, 30: Cursor, 31: Manifest, 32: eFileTypeRDLC+ """+ return ''++ def write(self):+ Logs.debug('msvs: creating %r' % self.path)+ template1 = compile_template(self.project_template)+ proj_str = template1(self)+ proj_str = rm_blank_lines(proj_str)+ self.path.stealth_write(proj_str)++ return dec++class msvs_2008_generator(msvs_generator):+ '''generates a visual studio 2008 solution'''+ cmd = 'msvs2008'+ fun = msvs_generator.fun++ def init(self):+ if not getattr(self, 'project_extension', None):+ self.project_extension = '_2008.vcproj'+ if not getattr(self, 'solution_name', None):+ self.solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '_2008.sln'++ if not getattr(self, 'vsnode_target', None):+ self.vsnode_target = wrap_2008(vsnode_target)+ if not getattr(self, 'vsnode_build_all', None):+ self.vsnode_build_all = wrap_2008(vsnode_build_all)+ if not getattr(self, 'vsnode_install_all', None):+ self.vsnode_install_all = wrap_2008(vsnode_install_all)+ if not getattr(self, 'vsnode_project_view', None):+ self.vsnode_project_view = wrap_2008(vsnode_project_view)++ msvs_generator.init(self)+ self.numver = '10.00'+ self.vsver = '2008'++def options(ctx):+ """+ If the msvs option is used, try to detect if the build is made from visual studio+ """+ ctx.add_option('--execsolution', action='store', help='when building with visual studio, use a build state file')++ old = BuildContext.execute+ def override_build_state(ctx):+ def lock(rm, add):+ uns = ctx.options.execsolution.replace('.sln', rm)+ uns = ctx.root.make_node(uns)+ try:+ uns.delete()+ except:+ pass++ uns = ctx.options.execsolution.replace('.sln', add)+ uns = ctx.root.make_node(uns)+ try:+ uns.write('')+ except:+ pass++ if ctx.options.execsolution:+ ctx.launch_dir = Context.top_dir # force a build for the whole project (invalid cwd when called by visual studio)+ lock('.lastbuildstate', '.unsuccessfulbuild')+ old(ctx)+ lock('.unsuccessfulbuild', '.lastbuildstate')+ else:+ old(ctx)+ BuildContext.execute = override_build_state+new file mode 100644@@ -0,0 +1,328 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2011 (ita)++"""+A client for the network cache (playground/netcache/). Launch the server with:+./netcache_server, then use it for the builds by adding the following:++ def options(opt):+ opt.load('netcache_client')++The parameters should be present in the environment in the form:+ NETCACHE=host:port@mode waf configure build++where:+ mode: PUSH, PULL, PUSH_PULL+ host: host where the server resides, for example 127.0.0.1+ port: by default the server runs on port 51200++The cache can be enabled for the build only:+ def options(opt):+ opt.load('netcache_client', funs=[])+ def build(bld):+ bld.setup_netcache('localhost', 51200, 'PUSH_PULL')+"""++import os, socket, time, atexit+from waflib import Task, Logs, Utils, Build, Options, Runner+from waflib.Configure import conf++BUF = 8192 * 16+HEADER_SIZE = 128+MODES = ['PUSH', 'PULL', 'PUSH_PULL']+STALE_TIME = 30 # seconds++GET = 'GET'+PUT = 'PUT'+LST = 'LST'+BYE = 'BYE'++all_sigs_in_cache = (0.0, [])++active_connections = Runner.Queue(0)+def get_connection():+ # return a new connection... do not forget to release it!+ try:+ ret = active_connections.get(block=False)+ except Exception:+ ret = socket.socket(socket.AF_INET, socket.SOCK_STREAM)+ ret.connect(Task.net_cache[:2])+ return ret++def release_connection(conn, msg=''):+ if conn:+ active_connections.put(conn)++def close_connection(conn, msg=''):+ if conn:+ data = '%s,%s' % (BYE, msg)+ try:+ conn.send(data.ljust(HEADER_SIZE))+ except:+ pass+ try:+ conn.close()+ except:+ pass++def close_all():+ while active_connections.qsize():+ conn = active_connections.get()+ try:+ close_connection(conn)+ except:+ pass+atexit.register(close_all)++def read_header(conn):+ cnt = 0+ buf = []+ while cnt < HEADER_SIZE:+ data = conn.recv(HEADER_SIZE - cnt)+ if not data:+ #import traceback+ #traceback.print_stack()+ raise ValueError('connection ended when reading a header %r' % buf)+ buf.append(data)+ cnt += len(data)+ return ''.join(buf)++def check_cache(conn, ssig):+ """+ List the files on the server, this is an optimization because it assumes that+ concurrent builds are rare+ """+ global all_sigs_in_cache+ if not STALE_TIME:+ return+ if time.time() - all_sigs_in_cache[0] > STALE_TIME:++ params = (LST,'')+ conn.send(','.join(params).ljust(HEADER_SIZE))++ # read what is coming back+ ret = read_header(conn)+ size = int(ret.split(',')[0])++ buf = []+ cnt = 0+ while cnt < size:+ data = conn.recv(min(BUF, size-cnt))+ if not data:+ raise ValueError('connection ended %r %r' % (cnt, size))+ buf.append(data)+ cnt += len(data)+ all_sigs_in_cache = (time.time(), ''.join(buf).split('\n'))+ Logs.debug('netcache: server cache has %r entries' % len(all_sigs_in_cache[1]))++ if not ssig in all_sigs_in_cache[1]:+ raise ValueError('no file %s in cache' % ssig)++class MissingFile(Exception):+ pass++def recv_file(conn, ssig, count, p):+ check_cache(conn, ssig)++ params = (GET, ssig, str(count))+ conn.send(','.join(params).ljust(HEADER_SIZE))+ data = read_header(conn)++ size = int(data.split(',')[0])++ if size == -1:+ raise MissingFile('no file %s - %s in cache' % (ssig, count))++ # get the file, writing immediately+ # TODO a tmp file would be better+ f = open(p, 'wb')+ cnt = 0+ while cnt < size:+ data = conn.recv(min(BUF, size-cnt))+ if not data:+ raise ValueError('connection ended %r %r' % (cnt, size))+ f.write(data)+ cnt += len(data)+ f.close()++def put_data(conn, ssig, cnt, p):+ #print "pushing %r %r %r" % (ssig, cnt, p)+ size = os.stat(p).st_size+ params = (PUT, ssig, str(cnt), str(size))+ conn.send(','.join(params).ljust(HEADER_SIZE))+ f = open(p, 'rb')+ cnt = 0+ while cnt < size:+ r = f.read(min(BUF, size-cnt))+ while r:+ k = conn.send(r)+ if not k:+ raise ValueError('connection ended')+ cnt += k+ r = r[k:]++#def put_data(conn, ssig, cnt, p):+# size = os.stat(p).st_size+# params = (PUT, ssig, str(cnt), str(size))+# conn.send(','.join(params).ljust(HEADER_SIZE))+# conn.send(','*size)+# params = (BYE, 'he')+# conn.send(','.join(params).ljust(HEADER_SIZE))++def can_retrieve_cache(self):+ if not Task.net_cache:+ return False+ if not self.outputs:+ return False+ if Task.net_cache[-1] == 'PUSH':+ return+ self.cached = False++ cnt = 0+ sig = self.signature()+ ssig = self.uid().encode('hex') + sig.encode('hex')++ conn = None+ err = False+ try:+ try:+ conn = get_connection()+ for node in self.outputs:+ p = node.abspath()+ recv_file(conn, ssig, cnt, p)+ cnt += 1+ except MissingFile as e:+ Logs.debug('netcache: file is not in the cache %r' % e)+ err = True++ except Exception as e:+ Logs.debug('netcache: could not get the files %r' % e)+ err = True++ # broken connection? remove this one+ close_connection(conn)+ conn = None+ finally:+ release_connection(conn)+ if err:+ return False++ for node in self.outputs:+ node.sig = sig+ #if self.generator.bld.progress_bar < 1:+ # self.generator.bld.to_log('restoring from cache %r\n' % node.abspath())++ self.cached = True+ return True++@Utils.run_once+def put_files_cache(self):+ if not Task.net_cache:+ return+ if not self.outputs:+ return+ if Task.net_cache[-1] == 'PULL':+ return+ if getattr(self, 'cached', None):+ return++ #print "called put_files_cache", id(self)+ bld = self.generator.bld+ sig = self.signature()+ ssig = self.uid().encode('hex') + sig.encode('hex')++ conn = None+ cnt = 0+ try:+ for node in self.outputs:+ # We could re-create the signature of the task with the signature of the outputs+ # in practice, this means hashing the output files+ # this is unnecessary+ try:+ if not conn:+ conn = get_connection()+ put_data(conn, ssig, cnt, node.abspath())+ except Exception as e:+ Logs.debug("netcache: could not push the files %r" % e)++ # broken connection? remove this one+ close_connection(conn)+ conn = None+ cnt += 1+ finally:+ release_connection(conn)++ bld.task_sigs[self.uid()] = self.cache_sig++def hash_env_vars(self, env, vars_lst):+ if not env.table:+ env = env.parent+ if not env:+ return Utils.SIG_NIL++ idx = str(id(env)) + str(vars_lst)+ try:+ cache = self.cache_env+ except AttributeError:+ cache = self.cache_env = {}+ else:+ try:+ return self.cache_env[idx]+ except KeyError:+ pass++ v = str([env[a] for a in vars_lst])+ v = v.replace(self.srcnode.abspath().__repr__()[:-1], '')+ m = Utils.md5()+ m.update(v.encode())+ ret = m.digest()++ Logs.debug('envhash: %r %r', ret, v)++ cache[idx] = ret++ return ret++def uid(self):+ try:+ return self.uid_+ except AttributeError:+ m = Utils.md5()+ src = self.generator.bld.srcnode+ up = m.update+ up(self.__class__.__name__.encode())+ for x in self.inputs + self.outputs:+ up(x.path_from(src).encode())+ self.uid_ = m.digest()+ return self.uid_++@conf+def setup_netcache(ctx, host, port, mode):+ Logs.warn('Using the network cache %s, %s, %s' % (host, port, mode))+ Task.net_cache = (host, port, mode)+ Task.Task.can_retrieve_cache = can_retrieve_cache+ Task.Task.put_files_cache = put_files_cache+ Task.Task.uid = uid+ Build.BuildContext.hash_env_vars = hash_env_vars+ ctx.cache_global = Options.cache_global = True++def options(opt):+ if not 'NETCACHE' in os.environ:+ Logs.warn('the network cache is disabled, set NETCACHE=host:port@mode to enable')+ else:+ v = os.environ['NETCACHE']+ if v in MODES:+ host = socket.gethostname()+ port = 51200+ mode = v+ else:+ mode = 'PUSH_PULL'+ host, port = v.split(':')+ if port.find('@'):+ port, mode = port.split('@')+ port = int(port)+ if not mode in MODES:+ opt.fatal('Invalid mode %s not in %r' % (mode, MODES))+ setup_netcache(opt, host, port, mode)+new file mode 100644@@ -0,0 +1,54 @@+#!/usr/bin/python+# Grygoriy Fuchedzhy 2010++"""+Support for converting linked targets to ihex, srec or binary files using+objcopy. Use the 'objcopy' feature in conjuction with the 'cc' or 'cxx'+feature. The 'objcopy' feature uses the following attributes:++objcopy_bfdname Target object format name (eg. ihex, srec, binary).+ Defaults to ihex.+objcopy_target File name used for objcopy output. This defaults to the+ target name with objcopy_bfdname as extension.+objcopy_install_path Install path for objcopy_target file. Defaults to ${PREFIX}/fw.+objcopy_flags Additional flags passed to objcopy.+"""++from waflib.Utils import def_attrs+from waflib import Task+from waflib.TaskGen import feature, after_method++class objcopy(Task.Task):+ run_str = '${OBJCOPY} -O ${TARGET_BFDNAME} ${OBJCOPYFLAGS} ${SRC} ${TGT}'+ color = 'CYAN'++@feature('objcopy')+@after_method('apply_link')+def objcopy(self):+ def_attrs(self,+ objcopy_bfdname = 'ihex',+ objcopy_target = None,+ objcopy_install_path = "${PREFIX}/firmware",+ objcopy_flags = '')++ link_output = self.link_task.outputs[0]+ if not self.objcopy_target:+ self.objcopy_target = link_output.change_ext('.' + self.objcopy_bfdname).name+ task = self.create_task('objcopy',+ src=link_output,+ tgt=self.path.find_or_declare(self.objcopy_target))++ task.env.append_unique('TARGET_BFDNAME', self.objcopy_bfdname)+ try:+ task.env.append_unique('OBJCOPYFLAGS', getattr(self, 'objcopy_flags'))+ except AttributeError:+ pass++ if self.objcopy_install_path:+ self.bld.install_files(self.objcopy_install_path,+ task.outputs[0],+ env=task.env.derive())++def configure(ctx):+ objcopy = ctx.find_program('objcopy', var='OBJCOPY', mandatory=True)+new file mode 100644@@ -0,0 +1,326 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2006-2010 (ita)++"ocaml support"++import os, re+from waflib import TaskGen, Utils, Task, Build+from waflib.Logs import error+from waflib.TaskGen import feature, before_method, after_method, extension++EXT_MLL = ['.mll']+EXT_MLY = ['.mly']+EXT_MLI = ['.mli']+EXT_MLC = ['.c']+EXT_ML = ['.ml']++open_re = re.compile('^\s*open\s+([a-zA-Z]+)(;;){0,1}$', re.M)+foo = re.compile(r"""(\(\*)|(\*\))|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^()*"'\\]*)""", re.M)+def filter_comments(txt):+ meh = [0]+ def repl(m):+ if m.group(1): meh[0] += 1+ elif m.group(2): meh[0] -= 1+ elif not meh[0]: return m.group(0)+ return ''+ return foo.sub(repl, txt)++def scan(self):+ node = self.inputs[0]+ code = filter_comments(node.read())++ global open_re+ names = []+ import_iterator = open_re.finditer(code)+ if import_iterator:+ for import_match in import_iterator:+ names.append(import_match.group(1))+ found_lst = []+ raw_lst = []+ for name in names:+ nd = None+ for x in self.incpaths:+ nd = x.find_resource(name.lower()+'.ml')+ if not nd: nd = x.find_resource(name+'.ml')+ if nd:+ found_lst.append(nd)+ break+ else:+ raw_lst.append(name)++ return (found_lst, raw_lst)++native_lst=['native', 'all', 'c_object']+bytecode_lst=['bytecode', 'all']++@feature('ocaml')+def init_ml(self):+ Utils.def_attrs(self,+ type = 'all',+ incpaths_lst = [],+ bld_incpaths_lst = [],+ mlltasks = [],+ mlytasks = [],+ mlitasks = [],+ native_tasks = [],+ bytecode_tasks = [],+ linktasks = [],+ bytecode_env = None,+ native_env = None,+ compiled_tasks = [],+ includes = '',+ uselib = '',+ are_deps_set = 0)++@feature('ocaml')+@after_method('init_ml')+def init_envs_ml(self):++ self.islibrary = getattr(self, 'islibrary', False)++ global native_lst, bytecode_lst+ self.native_env = None+ if self.type in native_lst:+ self.native_env = self.env.derive()+ if self.islibrary: self.native_env['OCALINKFLAGS'] = '-a'++ self.bytecode_env = None+ if self.type in bytecode_lst:+ self.bytecode_env = self.env.derive()+ if self.islibrary: self.bytecode_env['OCALINKFLAGS'] = '-a'++ if self.type == 'c_object':+ self.native_env.append_unique('OCALINKFLAGS_OPT', '-output-obj')++@feature('ocaml')+@before_method('apply_vars_ml')+@after_method('init_envs_ml')+def apply_incpaths_ml(self):+ inc_lst = self.includes.split()+ lst = self.incpaths_lst+ for dir in inc_lst:+ node = self.path.find_dir(dir)+ if not node:+ error("node not found: " + str(dir))+ continue+ if not node in lst:+ lst.append(node)+ self.bld_incpaths_lst.append(node)+ # now the nodes are added to self.incpaths_lst++@feature('ocaml')+@before_method('process_source')+def apply_vars_ml(self):+ for i in self.incpaths_lst:+ if self.bytecode_env:+ app = self.bytecode_env.append_value+ app('OCAMLPATH', ['-I', i.bldpath(), '-I', i.srcpath()])++ if self.native_env:+ app = self.native_env.append_value+ app('OCAMLPATH', ['-I', i.bldpath(), '-I', i.srcpath()])++ varnames = ['INCLUDES', 'OCAMLFLAGS', 'OCALINKFLAGS', 'OCALINKFLAGS_OPT']+ for name in self.uselib.split():+ for vname in varnames:+ cnt = self.env[vname+'_'+name]+ if cnt:+ if self.bytecode_env: self.bytecode_env.append_value(vname, cnt)+ if self.native_env: self.native_env.append_value(vname, cnt)++@feature('ocaml')+@after_method('process_source')+def apply_link_ml(self):++ if self.bytecode_env:+ ext = self.islibrary and '.cma' or '.run'++ linktask = self.create_task('ocalink')+ linktask.bytecode = 1+ linktask.set_outputs(self.path.find_or_declare(self.target + ext))+ linktask.env = self.bytecode_env+ self.linktasks.append(linktask)++ if self.native_env:+ if self.type == 'c_object': ext = '.o'+ elif self.islibrary: ext = '.cmxa'+ else: ext = ''++ linktask = self.create_task('ocalinkx')+ linktask.set_outputs(self.path.find_or_declare(self.target + ext))+ linktask.env = self.native_env+ self.linktasks.append(linktask)++ # we produce a .o file to be used by gcc+ self.compiled_tasks.append(linktask)++@extension(*EXT_MLL)+def mll_hook(self, node):+ mll_task = self.create_task('ocamllex', node, node.change_ext('.ml'))+ mll_task.env = self.native_env.derive()+ self.mlltasks.append(mll_task)++ self.source.append(mll_task.outputs[0])++@extension(*EXT_MLY)+def mly_hook(self, node):+ mly_task = self.create_task('ocamlyacc', node, [node.change_ext('.ml'), node.change_ext('.mli')])+ mly_task.env = self.native_env.derive()+ self.mlytasks.append(mly_task)+ self.source.append(mly_task.outputs[0])++ task = self.create_task('ocamlcmi', mly_task.outputs[1], mly_task.outputs[1].change_ext('.cmi'))+ task.env = self.native_env.derive()++@extension(*EXT_MLI)+def mli_hook(self, node):+ task = self.create_task('ocamlcmi', node, node.change_ext('.cmi'))+ task.env = self.native_env.derive()+ self.mlitasks.append(task)++@extension(*EXT_MLC)+def mlc_hook(self, node):+ task = self.create_task('ocamlcc', node, node.change_ext('.o'))+ task.env = self.native_env.derive()+ self.compiled_tasks.append(task)++@extension(*EXT_ML)+def ml_hook(self, node):+ if self.native_env:+ task = self.create_task('ocamlx', node, node.change_ext('.cmx'))+ task.env = self.native_env.derive()+ task.incpaths = self.bld_incpaths_lst+ self.native_tasks.append(task)++ if self.bytecode_env:+ task = self.create_task('ocaml', node, node.change_ext('.cmo'))+ task.env = self.bytecode_env.derive()+ task.bytecode = 1+ task.incpaths = self.bld_incpaths_lst+ self.bytecode_tasks.append(task)++def compile_may_start(self):++ if not getattr(self, 'flag_deps', ''):+ self.flag_deps = 1++ # the evil part is that we can only compute the dependencies after the+ # source files can be read (this means actually producing the source files)+ if getattr(self, 'bytecode', ''): alltasks = self.generator.bytecode_tasks+ else: alltasks = self.generator.native_tasks++ self.signature() # ensure that files are scanned - unfortunately+ tree = self.generator.bld+ env = self.env+ for node in self.inputs:+ lst = tree.node_deps[self.uid()]+ for depnode in lst:+ for t in alltasks:+ if t == self: continue+ if depnode in t.inputs:+ self.set_run_after(t)++ # TODO necessary to get the signature right - for now+ delattr(self, 'cache_sig')+ self.signature()++ return Task.Task.runnable_status(self)++class ocamlx(Task.Task):+ """native caml compilation"""+ color = 'GREEN'+ run_str = '${OCAMLOPT} ${OCAMLPATH} ${OCAMLFLAGS} ${OCAMLINCLUDES} -c -o ${TGT} ${SRC}'+ scan = scan+ runnable_status = compile_may_start++class ocaml(Task.Task):+ """bytecode caml compilation"""+ color = 'GREEN'+ run_str = '${OCAMLC} ${OCAMLPATH} ${OCAMLFLAGS} ${OCAMLINCLUDES} -c -o ${TGT} ${SRC}'+ scan = scan+ runnable_status = compile_may_start++class ocamlcmi(Task.Task):+ """interface generator (the .i files?)"""+ color = 'BLUE'+ run_str = '${OCAMLC} ${OCAMLPATH} ${OCAMLINCLUDES} -o ${TGT} -c ${SRC}'+ before = ['ocamlcc', 'ocaml', 'ocamlcc']++class ocamlcc(Task.Task):+ """ocaml to c interfaces"""+ color = 'GREEN'+ run_str = 'cd ${TGT[0].bld_dir()} && ${OCAMLOPT} ${OCAMLFLAGS} ${OCAMLPATH} ${OCAMLINCLUDES} -c ${SRC[0].abspath()}'++class ocamllex(Task.Task):+ """lexical generator"""+ color = 'BLUE'+ run_str = '${OCAMLLEX} ${SRC} -o ${TGT}'+ before = ['ocamlcmi', 'ocaml', 'ocamlcc']++class ocamlyacc(Task.Task):+ """parser generator"""+ color = 'BLUE'+ run_str = '${OCAMLYACC} -b ${TGT[0].bld_base(env)} ${SRC}'+ before = ['ocamlcmi', 'ocaml', 'ocamlcc']++def link_may_start(self):++ if getattr(self, 'bytecode', 0): alltasks = self.generator.bytecode_tasks+ else: alltasks = self.generator.native_tasks++ for x in alltasks:+ if not x.hasrun:+ return Task.ASK_LATER++ if not getattr(self, 'order', ''):++ # now reorder the inputs given the task dependencies+ # this part is difficult, we do not have a total order on the tasks+ # if the dependencies are wrong, this may not stop+ seen = []+ pendant = []+alltasks+ while pendant:+ task = pendant.pop(0)+ if task in seen: continue+ for x in task.run_after:+ if not x in seen:+ pendant.append(task)+ break+ else:+ seen.append(task)+ self.inputs = [x.outputs[0] for x in seen]+ self.order = 1+ return Task.Task.runnable_status(self)++class ocalink(Task.Task):+ """bytecode caml link"""+ color = 'YELLOW'+ run_str = '${OCAMLC} -o ${TGT} ${OCAMLINCLUDES} ${OCALINKFLAGS} ${SRC}'+ runnable_status = link_may_start+ after = ['ocaml', 'ocamlcc']++class ocalinkx(Task.Task):+ """native caml link"""+ color = 'YELLOW'+ run_str = '${OCAMLOPT} -o ${TGT} ${OCAMLINCLUDES} ${OCALINKFLAGS_OPT} ${SRC}'+ runnable_status = link_may_start+ after = ['ocamlx', 'ocamlcc']++def configure(conf):+ opt = conf.find_program('ocamlopt', var='OCAMLOPT', mandatory=False)+ occ = conf.find_program('ocamlc', var='OCAMLC', mandatory=False)+ if (not opt) or (not occ):+ conf.fatal('The objective caml compiler was not found:\ninstall it or make it available in your PATH')++ v = conf.env+ v['OCAMLC'] = occ+ v['OCAMLOPT'] = opt+ v['OCAMLLEX'] = conf.find_program('ocamllex', var='OCAMLLEX', mandatory=False)+ v['OCAMLYACC'] = conf.find_program('ocamlyacc', var='OCAMLYACC', mandatory=False)+ v['OCAMLFLAGS'] = ''+ v['OCAMLLIB'] = conf.cmd_and_log(conf.env['OCAMLC']+' -where').strip()+os.sep+ v['LIBPATH_OCAML'] = conf.cmd_and_log(conf.env['OCAMLC']+' -where').strip()+os.sep+ v['INCLUDES_OCAML'] = conf.cmd_and_log(conf.env['OCAMLC']+' -where').strip()+os.sep+ v['LIB_OCAML'] = 'camlrun'+new file mode 100644@@ -0,0 +1,76 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2011++"""+Obtain packages, unpack them in a location, and add associated uselib variables+(CFLAGS_pkgname, LIBPATH_pkgname, etc).++The default is use a Dependencies.txt file in the source directory.++This is a work in progress.++Usage:++def options(opt):+ opt.load('package')++def configure(conf):+ conf.load_packages()+"""++from waflib import Logs+from waflib.Configure import conf++try:+ from urllib import request+except:+ from urllib import urlopen+else:+ urlopen = request.urlopen+++CACHEVAR = 'WAFCACHE_PACKAGE'++@conf+def get_package_cache_dir(self):+ cache = None+ if CACHEVAR in conf.environ:+ cache = conf.environ[CACHEVAR]+ cache = self.root.make_node(cache)+ elif self.env[CACHEVAR]:+ cache = self.env[CACHEVAR]+ cache = self.root.make_node(cache)+ else:+ cache = self.srcnode.make_node('.wafcache_package')+ cache.mkdir()+ return cache++@conf+def download_archive(self, src, dst):+ for x in self.env.PACKAGE_REPO:+ url = '/'.join((x, src))+ try:+ web = urlopen(url)+ try:+ if web.getcode() != 200:+ continue+ except AttributeError:+ pass+ except Exception:+ # on python3 urlopen throws an exception+ # python 2.3 does not have getcode and throws an exception to fail+ continue+ else:+ tmp = self.root.make_node(dst)+ tmp.write(web.read())+ Logs.warn('Downloaded %s from %s' % (tmp.abspath(), url))+ break+ else:+ self.fatal('Could not get the package %s' % src)++@conf+def load_packages(self):+ cache = self.get_package_cache_dir()+ # read the dependencies, get the archives, ..+new file mode 100644@@ -0,0 +1,342 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2007-2010 (ita)++"""+Debugging helper for parallel compilation, outputs+a file named pdebug.svg in the source directory::++ def options(opt):+ opt.load('parallel_debug')+ def configure(conf):+ conf.load('parallel_debug')+ def build(bld):+ ...+"""++import os, time, sys+try: from Queue import Queue+except: from queue import Queue+from waflib import Runner, Options, Utils, Task, Logs, Errors++#import random+#random.seed(100)++def options(opt):+ opt.add_option('--dtitle', action='store', default='Parallel build representation for %r' % ' '.join(sys.argv),+ help='title for the svg diagram', dest='dtitle')+ opt.add_option('--dwidth', action='store', type='int', help='diagram width', default=800, dest='dwidth')+ opt.add_option('--dtime', action='store', type='float', help='recording interval in seconds', default=0.009, dest='dtime')+ opt.add_option('--dband', action='store', type='int', help='band width', default=22, dest='dband')+ opt.add_option('--dmaxtime', action='store', type='float', help='maximum time, for drawing fair comparisons', default=0, dest='dmaxtime')++# red #ff4d4d+# green #4da74d+# lila #a751ff++color2code = {+ 'GREEN' : '#4da74d',+ 'YELLOW' : '#fefe44',+ 'PINK' : '#a751ff',+ 'RED' : '#cc1d1d',+ 'BLUE' : '#6687bb',+ 'CYAN' : '#34e2e2',+}++mp = {}+info = [] # list of (text,color)++def map_to_color(name):+ if name in mp:+ return mp[name]+ try:+ cls = Task.classes[name]+ except KeyError:+ return color2code['RED']+ if cls.color in mp:+ return mp[cls.color]+ if cls.color in color2code:+ return color2code[cls.color]+ return color2code['RED']++def process(self):+ m = self.master+ if m.stop:+ m.out.put(self)+ return++ self.master.set_running(1, id(Utils.threading.currentThread()), self)++ # remove the task signature immediately before it is executed+ # in case of failure the task will be executed again+ try:+ del self.generator.bld.task_sigs[self.uid()]+ except:+ pass++ try:+ self.generator.bld.returned_tasks.append(self)+ self.log_display(self.generator.bld)+ ret = self.run()+ except Exception:+ self.err_msg = Utils.ex_stack()+ self.hasrun = Task.EXCEPTION++ # TODO cleanup+ m.error_handler(self)+ m.out.put(self)+ return++ if ret:+ self.err_code = ret+ self.hasrun = Task.CRASHED+ else:+ try:+ self.post_run()+ except Errors.WafError:+ pass+ except Exception:+ self.err_msg = Utils.ex_stack()+ self.hasrun = Task.EXCEPTION+ else:+ self.hasrun = Task.SUCCESS+ if self.hasrun != Task.SUCCESS:+ m.error_handler(self)++ self.master.set_running(-1, id(Utils.threading.currentThread()), self)+ m.out.put(self)+Task.TaskBase.process_back = Task.TaskBase.process+Task.TaskBase.process = process++old_start = Runner.Parallel.start+def do_start(self):+ try:+ Options.options.dband+ except AttributeError:+ self.bld.fatal('use def options(opt): opt.load("parallel_debug")!')++ self.taskinfo = Queue()+ old_start(self)+ if self.dirty:+ process_colors(self)+Runner.Parallel.start = do_start++def set_running(self, by, i, tsk):+ self.taskinfo.put( (i, id(tsk), time.time(), tsk.__class__.__name__, self.processed, self.count, by) )+Runner.Parallel.set_running = set_running++def name2class(name):+ return name.replace(' ', '_').replace('.', '_')++def process_colors(producer):+ # first, cast the parameters+ tmp = []+ try:+ while True:+ tup = producer.taskinfo.get(False)+ tmp.append(list(tup))+ except:+ pass++ try:+ ini = float(tmp[0][2])+ except:+ return++ if not info:+ seen = []+ for x in tmp:+ name = x[3]+ if not name in seen:+ seen.append(name)+ else:+ continue++ info.append((name, map_to_color(name)))+ info.sort(key=lambda x: x[0])++ thread_count = 0+ acc = []+ for x in tmp:+ thread_count += x[6]+ acc.append("%d %d %f %r %d %d %d" % (x[0], x[1], x[2] - ini, x[3], x[4], x[5], thread_count))+ data_node = producer.bld.path.make_node('pdebug.dat')+ data_node.write('\n'.join(acc))++ tmp = [lst[:2] + [float(lst[2]) - ini] + lst[3:] for lst in tmp]++ st = {}+ for l in tmp:+ if not l[0] in st:+ st[l[0]] = len(st.keys())+ tmp = [ [st[lst[0]]] + lst[1:] for lst in tmp ]+ THREAD_AMOUNT = len(st.keys())++ st = {}+ for l in tmp:+ if not l[1] in st:+ st[l[1]] = len(st.keys())+ tmp = [ [lst[0]] + [st[lst[1]]] + lst[2:] for lst in tmp ]+++ BAND = Options.options.dband++ seen = {}+ acc = []+ for x in range(len(tmp)):+ line = tmp[x]+ id = line[1]++ if id in seen:+ continue+ seen[id] = True++ begin = line[2]+ thread_id = line[0]+ for y in range(x + 1, len(tmp)):+ line = tmp[y]+ if line[1] == id:+ end = line[2]+ #print id, thread_id, begin, end+ #acc.append( ( 10*thread_id, 10*(thread_id+1), 10*begin, 10*end ) )+ acc.append( (BAND * begin, BAND*thread_id, BAND*end - BAND*begin, BAND, line[3]) )+ break++ if Options.options.dmaxtime < 0.1:+ gwidth = 1+ for x in tmp:+ m = BAND * x[2]+ if m > gwidth:+ gwidth = m+ else:+ gwidth = BAND * Options.options.dmaxtime++ ratio = float(Options.options.dwidth) / gwidth+ gwidth = Options.options.dwidth++ gheight = BAND * (THREAD_AMOUNT + len(info) + 1.5)++ out = []++ out.append("""<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>+<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"+\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">+<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.0\"+ x=\"%r\" y=\"%r\" width=\"%r\" height=\"%r\"+ id=\"svg602\" xml:space=\"preserve\">++<style type='text/css' media='screen'>+ g.over rect { stroke:#FF0000; fill-opacity:0.4 }+</style>++<script type='text/javascript'><![CDATA[+var svg = document.getElementsByTagName('svg')[0];++svg.addEventListener('mouseover', function(e) {+ var g = e.target.parentNode;+ var x = document.getElementById('r_' + g.id);+ if (x) {+ g.setAttribute('class', g.getAttribute('class') + ' over');+ x.setAttribute('class', x.getAttribute('class') + ' over');+ showInfo(e, g.id);+ }+}, false);++svg.addEventListener('mouseout', function(e) {+ var g = e.target.parentNode;+ var x = document.getElementById('r_' + g.id);+ if (x) {+ g.setAttribute('class', g.getAttribute('class').replace(' over', ''));+ x.setAttribute('class', x.getAttribute('class').replace(' over', ''));+ hideInfo(e);+ }+}, false);++function showInfo(evt, txt) {+ tooltip = document.getElementById('tooltip');++ var t = document.getElementById('tooltiptext');+ t.firstChild.data = txt;++ var x = evt.clientX + 9;+ if (x > 250) { x -= t.getComputedTextLength() + 16; }+ var y = evt.clientY + 20;+ tooltip.setAttribute("transform", "translate(" + x + "," + y + ")");+ tooltip.setAttributeNS(null, "visibility", "visible");++ var r = document.getElementById('tooltiprect');+ r.setAttribute('width', t.getComputedTextLength() + 6);+}++function hideInfo(evt) {+ var tooltip = document.getElementById('tooltip');+ tooltip.setAttributeNS(null,"visibility","hidden");+}+]]></script>++<!-- inkscape requires a big rectangle or it will not export the pictures properly -->+<rect+ x='%r' y='%r'+ width='%r' height='%r'+ style=\"font-size:10;fill:#ffffff;fill-opacity:0.01;fill-rule:evenodd;stroke:#ffffff;\"+ />\n++""" % (0, 0, gwidth + 4, gheight + 4, 0, 0, gwidth + 4, gheight + 4))++ # main title+ if Options.options.dtitle:+ out.append("""<text x="%d" y="%d" style="font-size:15px; text-anchor:middle; font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans">%s</text>+""" % (gwidth/2, gheight - 5, Options.options.dtitle))++ # the rectangles++ groups = {}+ for (x, y, w, h, clsname) in acc:+ try:+ groups[clsname].append((x, y, w, h))+ except:+ groups[clsname] = [(x, y, w, h)]+ for cls in groups:+ out.append("<g id='%s'>\n" % name2class(cls))++ for (x, y, w, h) in groups[cls]:+ out.append("""<rect+ x='%r' y='%r'+ width='%r' height='%r'+ style=\"font-size:10;fill:%s;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;\"+ />\n""" % (2 + x*ratio, 2 + y, w*ratio, h, map_to_color(cls)))+ out.append("</g>\n")++ # output the caption+ cnt = THREAD_AMOUNT++ for (text, color) in info:+ # caption box+ b = BAND/2+ out.append("""<g id='r_%s'><rect+ x='%r' y='%r'+ width='%r' height='%r'+ style=\"font-size:10;fill:%s;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;\"+ />\n""" % (name2class(text), 2 + BAND, 5 + (cnt + 0.5) * BAND, b, b, color))++ # caption text+ out.append("""<text+ style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"+ x="%r" y="%d">%s</text></g>\n""" % (2 + 2 * BAND, 5 + (cnt + 0.5) * BAND + 10, text))+ cnt += 1++ out.append("""+<g transform="translate(0,0)" visibility="hidden" id="tooltip">+ <rect id="tooltiprect" y="-15" x="-3" width="1" height="20" style="stroke:black;fill:#edefc2;stroke-width:1"/>+ <text id="tooltiptext" style="font-family:Arial; font-size:12;fill:black;"> </text>+</g>""")++ out.append("\n</svg>")++ node = producer.bld.path.make_node('pdebug.svg')+ node.write("".join(out))+ Logs.warn('Created the diagram %r' % node.abspath())++ p = node.parent.abspath()+ producer.bld.exec_command(['convert', p + os.sep + 'pdebug.svg', p + os.sep + 'pdebug.png'])+new file mode 100644@@ -0,0 +1,106 @@+#! /usr/bin/env python+# encoding: utf-8+#+# written by Sylvain Rouquette, 2011++'''+Install pep8 module:+$ easy_install pep8+ or+$ pip install pep8++To add the boost tool to the waf file:+$ ./waf-light --tools=compat15,pep8+ or, if you have waf >= 1.6.2+$ ./waf update --files=pep8+++Then add this to your wscript:++[at]extension('.py', 'wscript')+def run_pep8(self, node):+ self.create_task('Pep8', node)++'''++import threading+from waflib import TaskGen, Task, Options++pep8 = __import__('pep8')+++class Pep8(Task.Task):+ color = 'PINK'+ lock = threading.Lock()++ def check_options(self):+ if pep8.options:+ return+ pep8.options = Options.options+ pep8.options.prog = 'pep8'+ excl = pep8.options.exclude.split(',')+ pep8.options.exclude = [s.rstrip('/') for s in excl]+ if pep8.options.filename:+ pep8.options.filename = pep8.options.filename.split(',')+ if pep8.options.select:+ pep8.options.select = pep8.options.select.split(',')+ else:+ pep8.options.select = []+ if pep8.options.ignore:+ pep8.options.ignore = pep8.options.ignore.split(',')+ elif pep8.options.select:+ # Ignore all checks which are not explicitly selected+ pep8.options.ignore = ['']+ elif pep8.options.testsuite or pep8.options.doctest:+ # For doctest and testsuite, all checks are required+ pep8.options.ignore = []+ else:+ # The default choice: ignore controversial checks+ pep8.options.ignore = pep8.DEFAULT_IGNORE.split(',')+ pep8.options.physical_checks = pep8.find_checks('physical_line')+ pep8.options.logical_checks = pep8.find_checks('logical_line')+ pep8.options.counters = dict.fromkeys(pep8.BENCHMARK_KEYS, 0)+ pep8.options.messages = {}++ def run(self):+ with Pep8.lock:+ self.check_options()+ pep8.input_file(self.inputs[0].abspath())+ return 0 if not pep8.get_count() else -1+++def options(opt):+ opt.add_option('-q', '--quiet', default=0, action='count',+ help="report only file names, or nothing with -qq")+ opt.add_option('-r', '--repeat', action='store_true',+ help="show all occurrences of the same error")+ opt.add_option('--exclude', metavar='patterns',+ default=pep8.DEFAULT_EXCLUDE,+ help="exclude files or directories which match these "+ "comma separated patterns (default: %s)" %+ pep8.DEFAULT_EXCLUDE,+ dest='exclude')+ opt.add_option('--filename', metavar='patterns', default='*.py',+ help="when parsing directories, only check filenames "+ "matching these comma separated patterns (default: "+ "*.py)")+ opt.add_option('--select', metavar='errors', default='',+ help="select errors and warnings (e.g. E,W6)")+ opt.add_option('--ignore', metavar='errors', default='',+ help="skip errors and warnings (e.g. E4,W)")+ opt.add_option('--show-source', action='store_true',+ help="show source code for each error")+ opt.add_option('--show-pep8', action='store_true',+ help="show text of PEP 8 for each error")+ opt.add_option('--statistics', action='store_true',+ help="count errors and warnings")+ opt.add_option('--count', action='store_true',+ help="print total number of errors and warnings "+ "to standard error and set exit code to 1 if "+ "total is not null")+ opt.add_option('--benchmark', action='store_true',+ help="measure processing speed")+ opt.add_option('--testsuite', metavar='dir',+ help="run regression tests from dir")+ opt.add_option('--doctest', action='store_true',+ help="run doctest on myself")new file mode 100644@@ -0,0 +1,69 @@+#!/usr/bin/env python+# encoding: utf-8+# Antoine Dechaume 2011++"""+Detect the PGI C compiler+"""++import sys, re+from waflib.Configure import conf+from waflib.Tools.compiler_c import c_compiler+c_compiler['linux'].append('pgicc')++@conf+def find_pgi_compiler(conf, var, name):+ """+ Find the program name, and execute it to ensure it really is itself.+ """+ if sys.platform == 'cygwin':+ conf.fatal('The PGI compiler does not work on Cygwin')++ v = conf.env+ cc = None+ if v[var]: cc = v[var]+ elif var in conf.environ: cc = conf.environ[var]+ if not cc: cc = conf.find_program(name, var=var)+ if not cc: conf.fatal('PGI Compiler (%s) was not found' % name)+ cc = conf.cmd_to_list(cc)++ v[var + '_VERSION'] = conf.get_pgi_version(cc)+ v[var] = cc+ v[var + '_NAME'] = 'pgi'++@conf+def get_pgi_version(conf, cc):+ """Find the version of a pgi compiler."""+ version_re = re.compile(r"The Portland Group", re.I).search+ cmd = cc + ['-V', '-E'] # Issue 1078, prevent wrappers from linking++ try:+ out, err = conf.cmd_and_log(cmd, output=0)+ except Exception:+ conf.fatal('Could not find pgi compiler %r' % cmd)++ if out: match = version_re(out)+ else: match = version_re(err)++ if not match:+ conf.fatal('Could not verify PGI signature')++ cmd = cc + ['-help=variable']+ try:+ out, err = conf.cmd_and_log(cmd, output=0)+ except Exception:+ conf.fatal('Could not find pgi compiler %r' % cmd)++ version = re.findall('^COMPVER\s*=(.*)', out, re.M)+ if len(version) != 1:+ conf.fatal('Could not determine the compiler version')+ return version[0]++def configure(conf):+ conf.find_pgi_compiler('CC', 'pgcc')+ conf.find_ar()+ conf.gcc_common_flags()+ conf.cc_load_tools()+ conf.cc_add_flags()+ conf.link_add_flags()+new file mode 100644@@ -0,0 +1,22 @@+#!/usr/bin/env python+# encoding: utf-8+# Antoine Dechaume 2011++"""+Detect the PGI C++ compiler+"""++import sys, re+from waflib.Configure import conf+from waflib.Tools.compiler_cxx import cxx_compiler+cxx_compiler['linux'].append('pgicxx')++from waflib.extras import pgicc++def configure(conf):+ conf.find_pgi_compiler('CXX', 'pgCC')+ conf.find_ar()+ conf.gxx_common_flags()+ conf.cxx_load_tools()+ conf.cxx_add_flags()+ conf.link_add_flags()new file mode 100644@@ -0,0 +1,46 @@+#! /usr/bin/env python++"""+Illustrate how to override a class method to do something++In this case, print the commands being executed as strings+(the commands are usually lists, so this can be misleading)+"""++import sys+from waflib import Context, Utils, Logs++def exec_command(self, cmd, **kw):+ subprocess = Utils.subprocess+ kw['shell'] = isinstance(cmd, str)++ txt = cmd+ if isinstance(cmd, list):+ txt = ' '.join(cmd)++ print(txt)+ Logs.debug('runner_env: kw=%s' % kw)++ try:+ if self.logger:+ # warning: may deadlock with a lot of output (subprocess limitation)++ self.logger.info(cmd)++ kw['stdout'] = kw['stderr'] = subprocess.PIPE+ p = subprocess.Popen(cmd, **kw)+ (out, err) = p.communicate()+ if out:+ self.logger.debug('out: %s' % out.decode(sys.stdout.encoding or 'iso8859-1'))+ if err:+ self.logger.error('err: %s' % err.decode(sys.stdout.encoding or 'iso8859-1'))+ return p.returncode+ else:+ p = subprocess.Popen(cmd, **kw)+ return p.wait()+ except OSError:+ return -1++Context.Context.exec_command = exec_command++new file mode 100644@@ -0,0 +1,56 @@+#! /usr/bin/env python+# per rosengren 2011++from os import environ, path+from waflib import TaskGen, Utils++def options(opt):+ grp = opt.add_option_group('Oracle ProC Options')+ grp.add_option('--oracle_home', action='store', default=environ.get('PROC_ORACLE'), help='Path to Oracle installation home (has bin/lib)')+ grp.add_option('--tns_admin', action='store', default=environ.get('TNS_ADMIN'), help='Directory containing server list (TNS_NAMES.ORA)')+ grp.add_option('--connection', action='store', default='dummy-user/dummy-password@dummy-server', help='Format: user/password@server')++def configure(cnf):+ env = cnf.env+ if not env.PROC_ORACLE:+ env.PROC_ORACLE = cnf.options.oracle_home+ if not env.PROC_TNS_ADMIN:+ env.PROC_TNS_ADMIN = cnf.options.tns_admin+ if not env.PROC_CONNECTION:+ env.PROC_CONNECTION = cnf.options.connection+ cnf.find_program('proc', var='PROC', path_list=env.PROC_ORACLE + path.sep + 'bin')++def proc(tsk):+ env = tsk.env+ gen = tsk.generator+ bld = gen.bld+ inc_nodes = gen.to_incnodes(Utils.to_list(getattr(gen,'includes',[])) + env['INCLUDES'])++ # FIXME the if-else construct will not work in python 2+ cmd = (+ [env.PROC] ++ ['SQLCHECK=SEMANTICS'] ++ (['SYS_INCLUDE=(' + ','.join(env.PROC_INCLUDES) + ')']+ if env.PROC_INCLUDES else []) ++ ['INCLUDE=(' + ','.join(+ [i.bldpath() for i in inc_nodes]+ ) + ')'] ++ ['userid=' + env.PROC_CONNECTION] ++ ['INAME=' + tsk.inputs[0].bldpath()] ++ ['ONAME=' + tsk.outputs[0].bldpath()]+ )+ exec_env = {+ 'ORACLE_HOME': env.PROC_ORACLE,+ 'LD_LIBRARY_PATH': env.PROC_ORACLE + path.sep + 'lib',+ }+ if env.PROC_TNS_ADMIN:+ exec_env['TNS_ADMIN'] = env.PROC_TNS_ADMIN+ return tsk.exec_command(cmd, env=exec_env)++TaskGen.declare_chain(+ name = 'proc',+ rule = proc,+ ext_in = '.pc',+ ext_out = '.c',+)+new file mode 100644@@ -0,0 +1,47 @@+#!/usr/bin/env python+# encoding: utf-8+# Philipp Bender, 2012+# Matt Clarkson, 2012++from waflib.Task import Task+from waflib.TaskGen import extension ++"""+A simple tool to integrate protocol buffers into your build system.++ def configure(conf):+ conf.load('compiler_cxx cxx protoc')++ def build(bld):+ bld(+ features = 'cxx cxxprogram'+ source = 'main.cpp file1.proto proto/file2.proto', + include = '. proto',+ target = 'executable') ++"""++class protoc(Task):+ run_str = '${PROTOC} ${PROTOC_FLAGS} ${PROTOC_ST:INCPATHS} ${SRC[0].abspath()}'+ color = 'BLUE'+ ext_out = ['.h', 'pb.cc']++@extension('.proto')+def process_protoc(self, node):+ cpp_node = node.change_ext('.pb.cc')+ hpp_node = node.change_ext('.pb.h')+ self.create_task('protoc', node, [cpp_node, hpp_node])+ self.source.append(cpp_node)++ if 'cxx' in self.features and not self.env.PROTOC_FLAGS:+ self.env.PROTOC_FLAGS = '--cpp_out=.'++ use = getattr(self, 'use', '')+ if not 'PROTOBUF' in use:+ self.use = self.to_list(use) + ['PROTOBUF']++def configure(conf):+ conf.check_cfg(package="protobuf", uselib_store="PROTOBUF", args=['--cflags', '--libs'])+ conf.find_program('protoc', var='PROTOC')+ conf.env.PROTOC_ST = '-I%s'+new file mode 100644@@ -0,0 +1,74 @@+#!/usr/bin/env python+# encoding: utf-8+# Jérôme Carretero 2011 (zougloub)+# QNX neutrino compatibility functions++import sys, os+from waflib import Utils++class Popen(object):+ """+ Popen cannot work on QNX from a threaded program:+ Forking in threads is not implemented in neutrino.++ Python's os.popen / spawn / fork won't work when running in threads (they will if in the main program thread)++ In waf, this happens mostly in build.+ And the use cases can be replaced by os.system() calls.+ """+ __slots__ = ["prog", "kw", "popen", "verbose"]+ verbose = 0+ def __init__(self, prog, **kw):+ try:+ self.prog = prog+ self.kw = kw+ self.popen = None+ if Popen.verbose:+ sys.stdout.write("Popen created: %r, kw=%r..." % (prog, kw))++ do_delegate = kw.get('stdout', None) == -1 and kw.get('stderr', None) == -1+ if do_delegate:+ if Popen.verbose:+ print("Delegating to real Popen")+ self.popen = self.real_Popen(prog, **kw)+ else:+ if Popen.verbose:+ print("Emulating")+ except Exception as e:+ if Popen.verbose:+ print("Exception: %s" % e)+ raise++ def __getattr__(self, name):+ if Popen.verbose:+ sys.stdout.write("Getattr: %s..." % name)+ if name in Popen.__slots__:+ if Popen.verbose:+ print("In slots!")+ return object.__getattr__(self, name)+ else:+ if self.popen is not None:+ if Popen.verbose:+ print("from Popen")+ return getattr(self.popen, name)+ else:+ if name == "wait":+ return self.emu_wait+ else:+ raise Exception("subprocess emulation: not implemented: %s" % name)++ def emu_wait(self):+ if Popen.verbose:+ print("emulated wait (%r kw=%r)" % (self.prog, self.kw))+ if isinstance(self.prog, str):+ cmd = self.prog+ else:+ cmd = " ".join(self.prog)+ if 'cwd' in self.kw:+ cmd = 'cd "%s" && %s' % (self.kw['cwd'], cmd)+ return os.system(cmd)++if sys.platform == "qnx6":+ Popen.real_Popen = Utils.subprocess.Popen+ Utils.subprocess.Popen = Popen+new file mode 100644@@ -0,0 +1,85 @@+#! /usr/bin/env python+# encoding: utf-8++"""+Waf 1.6++Try to detect if the project directory was relocated, and if it was,+change the node representing the project directory. Just call:++ waf configure build++Note that if the project directory name changes, the signatures for the tasks using+files in that directory will change, causing a partial build.+"""++import os+from waflib import Build, ConfigSet, Task, Utils, Errors+from waflib.TaskGen import feature, before_method, after_method++EXTRA_LOCK = '.old_srcdir'++old1 = Build.BuildContext.store+def store(self):+ old1(self)+ db = os.path.join(self.variant_dir, EXTRA_LOCK)+ env = ConfigSet.ConfigSet()+ env.SRCDIR = self.srcnode.abspath()+ env.store(db)+Build.BuildContext.store = store++old2 = Build.BuildContext.init_dirs+def init_dirs(self):++ if not (os.path.isabs(self.top_dir) and os.path.isabs(self.out_dir)):+ raise Errors.WafError('The project was not configured: run "waf configure" first!')++ srcdir = None+ db = os.path.join(self.variant_dir, EXTRA_LOCK)+ env = ConfigSet.ConfigSet()+ try:+ env.load(db)+ srcdir = env.SRCDIR+ except:+ pass++ if srcdir:+ d = self.root.find_node(srcdir)+ if d and srcdir != self.top_dir and getattr(d, 'children', ''):+ srcnode = self.root.make_node(self.top_dir)+ print("relocating the source directory %r -> %r" % (srcdir, self.top_dir))+ srcnode.children = {}++ for (k, v) in d.children.items():+ srcnode.children[k] = v+ v.parent = srcnode+ d.children = {}++ old2(self)++Build.BuildContext.init_dirs = init_dirs+++def uid(self):+ try:+ return self.uid_+ except AttributeError:+ # this is not a real hot zone, but we want to avoid surprises here+ m = Utils.md5()+ up = m.update+ up(self.__class__.__name__.encode())+ for x in self.inputs + self.outputs:+ up(x.path_from(x.ctx.srcnode).encode())+ self.uid_ = m.digest()+ return self.uid_+Task.Task.uid = uid++@feature('c', 'cxx', 'd', 'go', 'asm', 'fc', 'includes')+@after_method('propagate_uselib_vars', 'process_source')+def apply_incpaths(self):+ lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env['INCLUDES'])+ self.includes_nodes = lst+ bld = self.bld+ self.env['INCPATHS'] = [x.is_child_of(bld.srcnode) and x.path_from(bld.bldnode) or x.abspath() for x in lst]++new file mode 100644@@ -0,0 +1,35 @@+#! /usr/bin/env python+# ++import os+from waflib import Task+from waflib.TaskGen import extension++def configure(conf):+ conf.find_program(['resgen'], var='RESGEN')+ conf.env.RESGENFLAGS = '/useSourcePath'++@extension('.resx')+def resx_file(self, node):+ """+ Bind the .resx extension to a resgen task+ """+ if not getattr(self, 'cs_task', None):+ self.bld.fatal('resx_file has no link task for use %r' % self)++ # Given assembly 'Foo' and file 'Sub/Dir/File.resx', create 'Foo.Sub.Dir.File.resources'+ assembly = os.path.splitext(self.gen)[0]+ res = os.path.splitext(node.path_from(self.path))[0].replace('/', '.')+ out = self.path.find_or_declare(assembly + '.' + res + '.resources')++ tsk = self.create_task('resgen', node, out)++ self.cs_task.dep_nodes.extend(tsk.outputs) # dependency+ self.env.append_value('RESOURCES', tsk.outputs[0].bldpath())++class resgen(Task.Task):+ """+ Compile C# resource files+ """+ color = 'YELLOW'+ run_str = '${RESGEN} ${RESGENFLAGS} ${SRC} ${TGT}'new file mode 100644@@ -0,0 +1,328 @@+#!/usr/bin/env python+# encoding: utf-8+# Laurent Birtz, 2011+# moved the code into a separate tool (ita)++"""+There are several things here:+- a different command-line option management making options persistent+- the review command to display the options set++Assumptions:+- configuration options are not always added to the right group (and do not count on the users to do it...)+- the options are persistent between the executions (waf options are NOT persistent by design), even for the configuration+- when the options change, the build is invalidated (forcing a reconfiguration)+"""++import os, textwrap, shutil+from waflib import Logs, Context, ConfigSet, Options, Build, Configure++class Odict(dict):+ """Ordered dictionary"""+ def __init__(self, data=None):+ self._keys = []+ dict.__init__(self)+ if data:+ # we were provided a regular dict+ if isinstance(data, dict):+ self.append_from_dict(data)++ # we were provided a tuple list+ elif type(data) == list:+ self.append_from_plist(data)++ # we were provided invalid input+ else:+ raise Exception("expected a dict or a tuple list")++ def append_from_dict(self, dict):+ map(self.__setitem__, dict.keys(), dict.values())++ def append_from_plist(self, plist):+ for pair in plist:+ if len(pair) != 2:+ raise Exception("invalid pairs list")+ for (k, v) in plist:+ self.__setitem__(k, v)++ def __delitem__(self, key):+ if not key in self._keys:+ raise KeyError(key)+ dict.__delitem__(self, key)+ self._keys.remove(key)++ def __setitem__(self, key, item):+ dict.__setitem__(self, key, item)+ if key not in self._keys:+ self._keys.append(key)++ def clear(self):+ dict.clear(self)+ self._keys = []++ def copy(self):+ return Odict(self.plist())++ def items(self):+ return zip(self._keys, self.values())++ def keys(self):+ return list(self._keys) # return a copy of the list++ def values(self):+ return map(self.get, self._keys)++ def plist(self):+ p = []+ for k, v in self.items():+ p.append( (k, v) )+ return p++ def __str__(self):+ s = "{"+ l = len(self._keys)+ for k, v in self.items():+ l -= 1+ strkey = str(k)+ if isinstance(k, basestring): strkey = "'"+strkey+"'"+ strval = str(v)+ if isinstance(v, basestring): strval = "'"+strval+"'"+ s += strkey + ":" + strval+ if l > 0: s += ", "+ s += "}"+ return s++review_options = Odict()+"""+Ordered dictionary mapping configuration option names to their optparse option.+"""++review_defaults = {}+"""+Dictionary mapping configuration option names to their default value.+"""++old_review_set = None+"""+Review set containing the configuration values before parsing the command line.+"""++new_review_set = None+"""+Review set containing the configuration values after parsing the command line.+"""++class OptionsReview(Options.OptionsContext):+ def __init__(self, **kw):+ super(self.__class__, self).__init__(**kw)++ def prepare_config_review(self):+ """+ Find the configuration options that are reviewable, detach+ their default value from their optparse object and store them+ into the review dictionaries.+ """+ gr = self.get_option_group('configure options')+ for opt in gr.option_list:+ if opt.action != 'store' or opt.dest in ("out", "top"):+ continue+ review_options[opt.dest] = opt+ review_defaults[opt.dest] = opt.default+ if gr.defaults.has_key(opt.dest):+ del gr.defaults[opt.dest]+ opt.default = None++ def parse_args(self):+ self.prepare_config_review()+ self.parser.get_option('--prefix').help = 'installation prefix'+ super(OptionsReview, self).parse_args()+ Context.create_context('review').refresh_review_set()++class ReviewContext(Context.Context):+ '''reviews the configuration values'''++ cmd = 'review'++ def __init__(self, **kw):+ super(self.__class__, self).__init__(**kw)++ out = Options.options.out+ if not out:+ out = getattr(Context.g_module, Context.OUT, None)+ if not out:+ out = Options.lockfile.replace('.lock-waf', '')+ self.build_path = (os.path.isabs(out) and self.root or self.path).make_node(out).abspath()+ """Path to the build directory"""++ self.cache_path = os.path.join(self.build_path, Build.CACHE_DIR)+ """Path to the cache directory"""++ self.review_path = os.path.join(self.cache_path, 'review.cache')+ """Path to the review cache file"""++ def execute(self):+ """+ Display and store the review set. Invalidate the cache as required.+ """+ if not self.compare_review_set(old_review_set, new_review_set):+ self.invalidate_cache()+ self.store_review_set(new_review_set)+ print(self.display_review_set(new_review_set))++ def invalidate_cache(self):+ """Invalidate the cache to prevent bad builds."""+ try:+ Logs.warn("Removing the cached configuration since the options have changed")+ shutil.rmtree(self.cache_path)+ except:+ pass++ def refresh_review_set(self):+ """+ Obtain the old review set and the new review set, and import the new set.+ """+ global old_review_set, new_review_set+ old_review_set = self.load_review_set()+ new_review_set = self.update_review_set(old_review_set)+ self.import_review_set(new_review_set)++ def load_review_set(self):+ """+ Load and return the review set from the cache if it exists.+ Otherwise, return an empty set.+ """+ if os.path.isfile(self.review_path):+ return ConfigSet.ConfigSet(self.review_path)+ return ConfigSet.ConfigSet()++ def store_review_set(self, review_set):+ """+ Store the review set specified in the cache.+ """+ if not os.path.isdir(self.cache_path):+ os.makedirs(self.cache_path)+ review_set.store(self.review_path)++ def update_review_set(self, old_set):+ """+ Merge the options passed on the command line with those imported+ from the previous review set and return the corresponding+ preview set.+ """++ # Convert value to string. It's important that 'None' maps to+ # the empty string.+ def val_to_str(val):+ if val == None or val == '':+ return ''+ return str(val)++ new_set = ConfigSet.ConfigSet()+ opt_dict = Options.options.__dict__++ for name in review_options.keys():+ # the option is specified explicitly on the command line+ if name in opt_dict:+ # if the option is the default, pretend it was never specified+ if val_to_str(opt_dict[name]) != val_to_str(review_defaults[name]):+ new_set[name] = opt_dict[name]+ # the option was explicitly specified in a previous command+ elif name in old_set:+ new_set[name] = old_set[name]++ return new_set++ def import_review_set(self, review_set):+ """+ Import the actual value of the reviewable options in the option+ dictionary, given the current review set.+ """+ for name in review_options.keys():+ if name in review_set:+ value = review_set[name]+ else:+ value = review_defaults[name]+ setattr(Options.options, name, value)++ def compare_review_set(self, set1, set2):+ """+ Return true if the review sets specified are equal.+ """+ if len(set1.keys()) != len(set2.keys()): return False+ for key in set1.keys():+ if not key in set2 or set1[key] != set2[key]:+ return False+ return True++ def display_review_set(self, review_set):+ """+ Return the string representing the review set specified.+ """+ term_width = Logs.get_term_cols()+ lines = []+ for dest in review_options.keys():+ opt = review_options[dest]+ name = ", ".join(opt._short_opts + opt._long_opts)+ help = opt.help+ actual = None+ if dest in review_set: actual = review_set[dest]+ default = review_defaults[dest]+ lines.append(self.format_option(name, help, actual, default, term_width))+ return "Configuration:\n\n" + "\n\n".join(lines) + "\n"++ def format_option(self, name, help, actual, default, term_width):+ """+ Return the string representing the option specified.+ """+ def val_to_str(val):+ if val == None or val == '':+ return "(void)"+ return str(val)++ max_name_len = 20+ sep_len = 2++ w = textwrap.TextWrapper()+ w.width = term_width - 1+ if w.width < 60: w.width = 60++ out = ""++ # format the help+ out += w.fill(help) + "\n"++ # format the name+ name_len = len(name)+ out += Logs.colors.CYAN + name + Logs.colors.NORMAL++ # set the indentation used when the value wraps to the next line+ w.subsequent_indent = " ".rjust(max_name_len + sep_len)+ w.width -= (max_name_len + sep_len)++ # the name string is too long, switch to the next line+ if name_len > max_name_len:+ out += "\n" + w.subsequent_indent++ # fill the remaining of the line with spaces+ else:+ out += " ".rjust(max_name_len + sep_len - name_len)++ # format the actual value, if there is one+ if actual != None:+ out += Logs.colors.BOLD + w.fill(val_to_str(actual)) + Logs.colors.NORMAL + "\n" + w.subsequent_indent++ # format the default value+ default_fmt = val_to_str(default)+ if actual != None:+ default_fmt = "default: " + default_fmt+ out += Logs.colors.NORMAL + w.fill(default_fmt) + Logs.colors.NORMAL++ return out++# Monkey-patch ConfigurationContext.execute() to have it store the review set.+old_configure_execute = Configure.ConfigurationContext.execute+def new_configure_execute(self):+ old_configure_execute(self)+ Context.create_context('review').store_review_set(new_review_set)+Configure.ConfigurationContext.execute = new_configure_execute+new file mode 100644@@ -0,0 +1,141 @@+#!/usr/bin/env python+# encoding: utf-8+# Hans-Martin von Gaudecker, 2012++"""+Run a Stata do-script in the directory specified by **ctx.bldnode**. The+first and only argument will be the name of the do-script (no extension),+which can be accessed inside the do-script by the local macro `1'. Useful+for keeping a log file.++The tool uses the log file that is automatically kept by Stata only +for error-catching purposes, it will be destroyed if the task finished+without error. In case of an error in **some_script.do**, you can inspect+it as **some_script.log** in the **ctx.bldnode** directory.++Note that Stata will not return an error code if it exits abnormally -- +catching errors relies on parsing the log file mentioned before. Should+the parser behave incorrectly please send an email to hmgaudecker [at] gmail.++**WARNING**++ The tool will not work if multiple do-scripts of the same name---but in+ different directories---are run at the same time! Avoid this situation.++Usage::++ ctx(features='run_do_script', + source='some_script.do',+ target=['some_table.tex', 'some_figure.eps'],+ deps='some_data.csv')+"""+++import os, re, sys+from waflib import Task, TaskGen, Logs++if sys.platform == 'darwin':+ STATA_COMMANDS = ['Stata64MP', 'StataMP',+ 'Stata64SE', 'StataSE', + 'Stata64', 'Stata']+ STATAFLAGS = '-e -q do'+ STATAENCODING = 'MacRoman'+elif sys.platform.startswith('linux'):+ STATA_COMMANDS = ['stata-mp', 'stata-se', 'stata']+ STATAFLAGS = '-b -q do'+ # Not sure whether this is correct...+ STATAENCODING = 'Latin-1'+elif sys.platform.lower().startswith('win'):+ STATA_COMMANDS = ['StataMP-64', 'StataMP-ia',+ 'StataMP', 'StataSE-64',+ 'StataSE-ia', 'StataSE',+ 'Stata-64', 'Stata-ia',+ 'Stata.e', 'WMPSTATA',+ 'WSESTATA', 'WSTATA']+ STATAFLAGS = '/e do'+ STATAENCODING = 'Latin-1'+else:+ raise Exception("Unknown sys.platform: %s " % sys.platform)++def configure(ctx):+ ctx.find_program(STATA_COMMANDS, var='STATACMD', errmsg="""\n+No Stata executable found!\n\n+If Stata is needed:\n+ 1) Check the settings of your system path.+ 2) Note we are looking for Stata executables called: %s+ If yours has a different name, please report to hmgaudecker [at] gmail\n+Else:\n+ Do not load the 'run_do_script' tool in the main wscript.\n\n""" % STATA_COMMANDS)+ ctx.env.STATAFLAGS = STATAFLAGS+ ctx.env.STATAENCODING = STATAENCODING++@Task.update_outputs+class run_do_script_base(Task.Task):+ """Run a Stata do-script from the bldnode directory."""+ run_str = '"${STATACMD}" ${STATAFLAGS} "${SRC[0].abspath()}" "${DOFILETRUNK}"'+ shell = True++class run_do_script(run_do_script_base):+ """Use the log file automatically kept by Stata for error-catching.+ Erase it if the task finished without error. If not, it will show + up as do_script.log in the bldnode directory.+ """+ def run(self):+ run_do_script_base.run(self)+ ret, log_tail = self.check_erase_log_file()+ if ret:+ Logs.error("""Running Stata on %s failed with code %r.\n\nCheck the log file %s, last 10 lines\n\n%s\n\n\n""" % (+ self.inputs[0].nice_path(), ret, self.env.LOGFILEPATH, log_tail))+ return ret++ def check_erase_log_file(self):+ """Parse Stata's default log file and erase it if everything okay.++ Parser is based on Brendan Halpin's shell script found here:+ http://teaching.sociology.ul.ie/bhalpin/wordpress/?p=122+ """++ if sys.version_info.major >= 3:+ kwargs = {'file': self.env.LOGFILEPATH, 'mode': 'r', 'encoding': self.env.STATAENCODING}+ else:+ kwargs = {'name': self.env.LOGFILEPATH, 'mode': 'r'}+ + with open(**kwargs) as log:+ log_tail = log.readlines()[-10:]+ for line in log_tail:+ error_found = re.match("r\(([0-9]+)\)", line)+ if error_found:+ return error_found.group(1), ''.join(log_tail)+ else:+ pass+ # Only end up here if the parser did not identify an error.+ os.remove(self.env.LOGFILEPATH)+ return None, None+++@TaskGen.feature('run_do_script')+@TaskGen.before_method('process_source')+def apply_run_do_script(tg):+ """Task generator customising the options etc. to call Stata in batch+ mode for running a do-script.+ """++ # Convert sources and targets to nodes+ src_node = tg.path.find_resource(tg.source)+ tgt_nodes = [tg.path.find_or_declare(t) for t in tg.to_list(tg.target)]++ tsk = tg.create_task('run_do_script', src=src_node, tgt=tgt_nodes)+ tsk.env.DOFILETRUNK = os.path.splitext(src_node.name)[0]+ tsk.env.LOGFILEPATH = os.path.join(tg.bld.bldnode.abspath(), '%s.log' % (tsk.env.DOFILETRUNK))++ # dependencies (if the attribute 'deps' changes, trigger a recompilation)+ for x in tg.to_list(getattr(tg, 'deps', [])):+ node = tg.path.find_resource(x)+ if not node:+ tg.bld.fatal('Could not find dependency %r for running %r' % (x, src_node.nice_path()))+ tsk.dep_nodes.append(node)+ Logs.debug('deps: found dependencies %r for running %r' % (tsk.dep_nodes, src_node.nice_path()))++ # Bypass the execution of process_source by setting the source to an empty list+ tg.source = []+new file mode 100644@@ -0,0 +1,89 @@+#!/usr/bin/env python+# encoding: utf-8+# Hans-Martin von Gaudecker, 2012++"""+Run a Matlab script.++Note that the script is run in the directory where it lives -- Matlab won't+allow it any other way.++For error-catching purposes, keep an own log-file that is destroyed if the+task finished without error. If not, it will show up as mscript_[index].log +in the bldnode directory.++Usage::++ ctx(features='run_m_script', + source='some_script.m',+ target=['some_table.tex', 'some_figure.eps'],+ deps='some_data.mat')+"""++import os, sys+from waflib import Task, TaskGen, Logs++MATLAB_COMMANDS = ['matlab']++def configure(ctx):+ ctx.find_program(MATLAB_COMMANDS, var='MATLABCMD', errmsg = """\n+No Matlab executable found!\n\n+If Matlab is needed:\n+ 1) Check the settings of your system path.+ 2) Note we are looking for Matlab executables called: %s+ If yours has a different name, please report to hmgaudecker [at] gmail\n+Else:\n+ Do not load the 'run_m_script' tool in the main wscript.\n\n""" % MATLAB_COMMANDS)+ ctx.env.MATLABFLAGS = '-wait -nojvm -nosplash -minimize'++@Task.update_outputs+class run_m_script_base(Task.Task):+ """Run a Matlab script."""+ run_str = '"${MATLABCMD}" ${MATLABFLAGS} -logfile "${LOGFILEPATH}" -r "try, ${MSCRIPTTRUNK}, exit(0), catch err, disp(err.getReport()), exit(1), end"'+ shell = True++class run_m_script(run_m_script_base):+ """Erase the Matlab overall log file if everything went okay, else raise an+ error and print its 10 last lines.+ """+ def run(self):+ ret = run_m_script_base.run(self)+ logfile = self.env.LOGFILEPATH+ if ret:+ mode = 'r'+ if sys.version_info.major >= 3:+ mode = 'rb'+ with open(logfile, mode=mode) as f:+ tail = f.readlines()[-10:]+ Logs.error("""Running Matlab on %s returned the error %r\n\nCheck the log file %s, last 10 lines\n\n%s\n\n\n""" % (+ self.inputs[0].nice_path(), ret, logfile, '\n'.join(tail)))+ else:+ os.remove(logfile)+ return ret++@TaskGen.feature('run_m_script')+@TaskGen.before_method('process_source')+def apply_run_m_script(tg):+ """Task generator customising the options etc. to call Matlab in batch+ mode for running a m-script.+ """++ # Convert sources and targets to nodes + src_node = tg.path.find_resource(tg.source)+ tgt_nodes = [tg.path.find_or_declare(t) for t in tg.to_list(tg.target)]++ tsk = tg.create_task('run_m_script', src=src_node, tgt=tgt_nodes)+ tsk.cwd = src_node.parent.abspath()+ tsk.env.MSCRIPTTRUNK = os.path.splitext(src_node.name)[0]+ tsk.env.LOGFILEPATH = os.path.join(tg.bld.bldnode.abspath(), '%s_%d.log' % (tsk.env.MSCRIPTTRUNK, tg.idx))++ # dependencies (if the attribute 'deps' changes, trigger a recompilation)+ for x in tg.to_list(getattr(tg, 'deps', [])):+ node = tg.path.find_resource(x)+ if not node:+ tg.bld.fatal('Could not find dependency %r for running %r' % (x, src_node.nice_path()))+ tsk.dep_nodes.append(node)+ Logs.debug('deps: found dependencies %r for running %r' % (tsk.dep_nodes, src_node.nice_path()))++ # Bypass the execution of process_source by setting the source to an empty list+ tg.source = []new file mode 100644@@ -0,0 +1,106 @@+#!/usr/bin/env python+# encoding: utf-8+# Hans-Martin von Gaudecker, 2012++"""+Run a Python script in the directory specified by **ctx.bldnode**.++Select a Python version by specifying the **version** keyword for+the task generator instance as integer 2 or 3. Default is 3.++If the build environment has an attribute "PROJECT_PATHS" with+a key "PROJECT_ROOT", its value will be appended to the PYTHONPATH.+Same a string passed to the optional **add_to_pythonpath**+keyword (appended after the PROJECT_ROOT).++Usage::++ ctx(features='run_py_script', version=3,+ source='some_script.py',+ target=['some_table.tex', 'some_figure.eps'],+ deps='some_data.csv',+ add_to_pythonpath='src/some/library')+"""++import os, re+from waflib import Task, TaskGen, Logs+++def configure(conf):+ """TODO: Might need to be updated for Windows once+ "PEP 397":http://www.python.org/dev/peps/pep-0397/ is settled.+ """+ conf.find_program('python', var='PY2CMD', mandatory=False)+ conf.find_program('python3', var='PY3CMD', mandatory=False)+ if not conf.env.PY2CMD and not conf.env.PY3CMD:+ conf.fatal("No Python interpreter found!")++@Task.update_outputs+class run_py_2_script(Task.Task):+ """Run a Python 2 script."""+ run_str = '${PY2CMD} ${SRC[0].abspath()}'+ shell=True++@Task.update_outputs+class run_py_3_script(Task.Task):+ """Run a Python 3 script."""+ run_str = '${PY3CMD} ${SRC[0].abspath()}'+ shell=True++@TaskGen.feature('run_py_script')+@TaskGen.before_method('process_source')+def apply_run_py_script(tg):+ """Task generator for running either Python 2 or Python 3 on a single+ script. + + Attributes:++ * source -- A **single** source node or string. (required)+ * target -- A single target or list of targets (nodes or strings). + * deps -- A single dependency or list of dependencies (nodes or strings)+ * add_to_pythonpath -- A string that will be appended to the PYTHONPATH environment variable.+ + If the build environment has an attribute "PROJECT_PATHS" with+ a key "PROJECT_ROOT", its value will be appended to the PYTHONPATH.+ + """++ # Set the Python version to use, default to 3.+ v = getattr(tg, 'version', 3)+ if v not in (2, 3): raise ValueError("Specify the 'version' attribute for run_py_script task generator as integer 2 or 3.\n Got: %s" %v)++ # Convert sources and targets to nodes + src_node = tg.path.find_resource(tg.source)+ tgt_nodes = [tg.path.find_or_declare(t) for t in tg.to_list(tg.target)]++ # Create the task.+ tsk = tg.create_task('run_py_%d_script' %v, src=src_node, tgt=tgt_nodes)++ # custom execution environment+ # TODO use a list and os.sep.join(lst) at the end instead of concatenating strings+ tsk.env.env = dict(os.environ)+ tsk.env.env['PYTHONPATH'] = tsk.env.env.get('PYTHONPATH', '')+ project_paths = getattr(tsk.env, 'PROJECT_PATHS', None)+ if project_paths and 'PROJECT_ROOT' in project_paths:+ tsk.env.env['PYTHONPATH'] += os.pathsep + project_paths['PROJECT_ROOT'].abspath()+ if getattr(tg, 'add_to_pythonpath', None):+ tsk.env.env['PYTHONPATH'] += os.pathsep + tg.add_to_pythonpath++ # Clean up the PYTHONPATH -- replace double occurrences of path separator + tsk.env.env['PYTHONPATH'] = re.sub(os.pathsep + '+', os.pathsep, tsk.env.env['PYTHONPATH'])++ # Clean up the PYTHONPATH -- doesn't like starting with path separator+ if tsk.env.env['PYTHONPATH'].startswith(os.pathsep):+ tsk.env.env['PYTHONPATH'] = tsk.env.env['PYTHONPATH'][1:]++ # dependencies (if the attribute 'deps' changes, trigger a recompilation)+ for x in tg.to_list(getattr(tg, 'deps', [])):+ node = tg.path.find_resource(x)+ if not node:+ tg.bld.fatal('Could not find dependency %r for running %r' % (x, src_node.nice_path()))+ tsk.dep_nodes.append(node)+ Logs.debug('deps: found dependencies %r for running %r' % (tsk.dep_nodes, src_node.nice_path()))++ # Bypass the execution of process_source by setting the source to an empty list+ tg.source = []+new file mode 100644@@ -0,0 +1,87 @@+#!/usr/bin/env python+# encoding: utf-8+# Hans-Martin von Gaudecker, 2012++"""+Run a R script in the directory specified by **ctx.bldnode**.++For error-catching purposes, keep an own log-file that is destroyed if the+task finished without error. If not, it will show up as rscript_[index].log +in the bldnode directory.++Usage::++ ctx(features='run_r_script', + source='some_script.r',+ target=['some_table.tex', 'some_figure.eps'],+ deps='some_data.csv')+"""+++import os, sys+from waflib import Task, TaskGen, Logs++R_COMMANDS = ['RTerm', 'R', 'r']++def configure(ctx):+ ctx.find_program(R_COMMANDS, var='RCMD', errmsg = """\n+No R executable found!\n\n+If R is needed:\n+ 1) Check the settings of your system path.+ 2) Note we are looking for R executables called: %s+ If yours has a different name, please report to hmgaudecker [at] gmail\n+Else:\n+ Do not load the 'run_r_script' tool in the main wscript.\n\n""" % R_COMMANDS)+ ctx.env.RFLAGS = 'CMD BATCH --slave'++@Task.update_outputs+class run_r_script_base(Task.Task):+ """Run a R script."""+ run_str = '"${RCMD}" ${RFLAGS} "${SRC[0].abspath()}" "${LOGFILEPATH}"'+ shell = True++class run_r_script(run_r_script_base):+ """Erase the R overall log file if everything went okay, else raise an+ error and print its 10 last lines.+ """+ def run(self):+ ret = run_r_script_base.run(self)+ logfile = self.env.LOGFILEPATH+ if ret:+ mode = 'r'+ if sys.version_info.major >= 3:+ mode = 'rb'+ with open(logfile, mode=mode) as f:+ tail = f.readlines()[-10:]+ Logs.error("""Running R on %s returned the error %r\n\nCheck the log file %s, last 10 lines\n\n%s\n\n\n""" % (+ self.inputs[0].nice_path(), ret, logfile, '\n'.join(tail)))+ else:+ os.remove(logfile)+ return ret+++@TaskGen.feature('run_r_script')+@TaskGen.before_method('process_source')+def apply_run_r_script(tg):+ """Task generator customising the options etc. to call R in batch+ mode for running a R script.+ """++ # Convert sources and targets to nodes+ src_node = tg.path.find_resource(tg.source)+ tgt_nodes = [tg.path.find_or_declare(t) for t in tg.to_list(tg.target)]++ tsk = tg.create_task('run_r_script', src=src_node, tgt=tgt_nodes)+ tsk.env.LOGFILEPATH = os.path.join(tg.bld.bldnode.abspath(), '%s_%d.log' % (os.path.splitext(src_node.name)[0], tg.idx))++ # dependencies (if the attribute 'deps' changes, trigger a recompilation)+ for x in tg.to_list(getattr(tg, 'deps', [])):+ node = tg.path.find_resource(x)+ if not node:+ tg.bld.fatal('Could not find dependency %r for running %r' % (x, src_node.nice_path()))+ tsk.dep_nodes.append(node)+ Logs.debug('deps: found dependencies %r for running %r' % (tsk.dep_nodes, src_node.nice_path()))++ # Bypass the execution of process_source by setting the source to an empty list+ tg.source = []+new file mode 100644@@ -0,0 +1,71 @@+#!/usr/bin/env python+# encoding: utf-8+# Mark Coggeshall, 2010++"SAS support"++import os, re+from waflib import Utils, Task, TaskGen, Runner, Build, Errors, Node, Logs+from waflib.TaskGen import feature, before_method++sas_fun, _ = Task.compile_fun('sas -sysin ${SRCFILE} -log ${LOGFILE} -print ${LSTFILE}', shell=False)++class sas(Task.Task):+ vars = ['SAS', 'SASFLAGS']+ def run(task):+ command = 'SAS'+ env = task.env+ bld = task.generator.bld++ fun = sas_fun++ node = task.inputs[0]+ logfilenode = node.change_ext('.log')+ lstfilenode = node.change_ext('.lst')++ # set the cwd+ task.cwd = task.inputs[0].parent.get_src().abspath()+ Logs.debug('runner: %s on %s' % (command, node.abspath))++ SASINPUTS = node.parent.get_bld().abspath() + os.pathsep + node.parent.get_src().abspath() + os.pathsep+ task.env.env = {'SASINPUTS': SASINPUTS}++ task.env.SRCFILE = node.abspath()+ task.env.LOGFILE = logfilenode.abspath()+ task.env.LSTFILE = lstfilenode.abspath()+ ret = fun(task)+ if ret:+ Logs.error('Running %s on %r returned a non-zero exit' % (command, node))+ Logs.error('SRCFILE = %r' % node)+ Logs.error('LOGFILE = %r' % logfilenode)+ Logs.error('LSTFILE = %r' % lstfilenode)+ return ret++@feature('sas')+@before_method('process_source')+def apply_sas(self):+ if not getattr(self, 'type', None) in ['sas']:+ self.type = 'sas'++ self.env['logdir'] = getattr(self, 'logdir', 'log')+ self.env['lstdir'] = getattr(self, 'lstdir', 'lst')++ deps_lst = []++ if getattr(self, 'deps', None):+ deps = self.to_list(self.deps)+ for filename in deps:+ n = self.path.find_resource(filename)+ if not n: n = self.bld.root.find_resource(filename)+ if not n: raise Errors.WafError('cannot find input file %s for processing' % filename)+ if not n in deps_lst: deps_lst.append(n)++ for node in self.to_nodes(self.source):+ if self.type == 'sas':+ task = self.create_task('sas', src=node)+ task.dep_nodes = deps_lst+ self.source = []++def configure(self):+ self.find_program('sas', var='SAS', mandatory=False)+new file mode 100644@@ -0,0 +1,130 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010 (ita)++"""+Scala support++scalac outputs files a bit where it wants to+"""++import os, re+from waflib.Configure import conf+from waflib import TaskGen, Task, Utils, Options, Build, Errors, Node+from waflib.TaskGen import feature, before_method, after_method++from waflib.Tools import ccroot+ccroot.USELIB_VARS['scalac'] = set(['CLASSPATH', 'SCALACFLAGS'])++from waflib.Tools import javaw++@feature('scalac')+@before_method('process_source')+def apply_scalac(self):++ Utils.def_attrs(self, jarname='', classpath='',+ sourcepath='.', srcdir='.',+ jar_mf_attributes={}, jar_mf_classpath=[])++ nodes_lst = []++ outdir = getattr(self, 'outdir', None)+ if outdir:+ if not isinstance(outdir, Node.Node):+ outdir = self.path.get_bld().make_node(self.outdir)+ else:+ outdir = self.path.get_bld()+ outdir.mkdir()+ self.env['OUTDIR'] = outdir.abspath()++ self.scalac_task = tsk = self.create_task('scalac')+ tmp = []++ srcdir = getattr(self, 'srcdir', '')+ if isinstance(srcdir, Node.Node):+ srcdir = [srcdir]+ for x in Utils.to_list(srcdir):+ if isinstance(x, Node.Node):+ y = x+ else:+ y = self.path.find_dir(x)+ if not y:+ self.bld.fatal('Could not find the folder %s from %s' % (x, self.path))+ tmp.append(y)+ tsk.srcdir = tmp++# reuse some code+feature('scalac')(javaw.use_javac_files)+after_method('apply_scalac')(javaw.use_javac_files)++feature('scalac')(javaw.set_classpath)+after_method('apply_scalac', 'use_scalac_files')(javaw.set_classpath)+++SOURCE_RE = '**/*.scala'+class scalac(javaw.javac):+ color = 'GREEN'+ vars = ['CLASSPATH', 'SCALACFLAGS', 'SCALAC', 'OUTDIR']++ def runnable_status(self):+ """+ Wait for dependent tasks to be complete, then read the file system to find the input nodes.+ """+ for t in self.run_after:+ if not t.hasrun:+ return Task.ASK_LATER++ if not self.inputs:+ global SOURCE_RE+ self.inputs = []+ for x in self.srcdir:+ self.inputs.extend(x.ant_glob(SOURCE_RE, remove=False))+ return super(javaw.javac, self).runnable_status()++ def run(self):+ """+ Execute the scalac compiler+ """+ env = self.env+ gen = self.generator+ bld = gen.bld+ wd = bld.bldnode.abspath()+ def to_list(xx):+ if isinstance(xx, str): return [xx]+ return xx+ self.last_cmd = lst = []+ lst.extend(to_list(env['SCALAC']))+ lst.extend(['-classpath'])+ lst.extend(to_list(env['CLASSPATH']))+ lst.extend(['-d'])+ lst.extend(to_list(env['OUTDIR']))+ lst.extend(to_list(env['SCALACFLAGS']))+ lst.extend([a.abspath() for a in self.inputs])+ lst = [x for x in lst if x]+ try:+ self.out = self.generator.bld.cmd_and_log(lst, cwd=wd, env=env.env or None, output=0, quiet=0)[1]+ except:+ self.generator.bld.cmd_and_log(lst, cwd=wd, env=env.env or None)++def configure(self):+ """+ Detect the scalac program+ """+ # If SCALA_HOME is set, we prepend it to the path list+ java_path = self.environ['PATH'].split(os.pathsep)+ v = self.env++ if 'SCALA_HOME' in self.environ:+ java_path = [os.path.join(self.environ['SCALA_HOME'], 'bin')] + java_path+ self.env['SCALA_HOME'] = [self.environ['SCALA_HOME']]++ for x in 'scalac scala'.split():+ self.find_program(x, var=x.upper(), path_list=java_path)+ self.env[x.upper()] = self.cmd_to_list(self.env[x.upper()])++ if 'CLASSPATH' in self.environ:+ v['CLASSPATH'] = self.environ['CLASSPATH']++ v.SCALACFLAGS = ['-verbose']+ if not v['SCALAC']: self.fatal('scalac is required for compiling scala classes')+new file mode 100644@@ -0,0 +1,95 @@+#! /usr/bin/env python+# Thomas Nagy, 2011 (ita)++"""+Create _moc.cpp files++The builds are 30-40% faster when .moc files are included,+you should NOT use this tool. If you really+really want it:++def configure(conf):+ conf.load('compiler_cxx qt4')+ conf.load('slow_qt4')++See playground/slow_qt/wscript for a complete example.+"""++from waflib.TaskGen import extension+from waflib import Task+import waflib.Tools.qt4+import waflib.Tools.cxx++@extension(*waflib.Tools.qt4.EXT_QT4)+def cxx_hook(self, node):+ self.create_compiled_task('cxx_qt', node)++class cxx_qt(waflib.Tools.cxx.cxx):+ def runnable_status(self):+ ret = waflib.Tools.cxx.cxx.runnable_status(self)+ if ret != Task.ASK_LATER and not getattr(self, 'moc_done', None):++ try:+ cache = self.generator.moc_cache+ except AttributeError:+ cache = self.generator.moc_cache = {}++ deps = self.generator.bld.node_deps[self.uid()]+ for x in [self.inputs[0]] + deps:+ if x.read().find('Q_OBJECT') > 0:++ # process "foo.h -> foo.moc" only if "foo.cpp" is in the sources for the current task generator+ # this code will work because it is in the main thread (runnable_status)+ if x.name.rfind('.') > -1: # a .h file...+ name = x.name[:x.name.rfind('.')]+ for tsk in self.generator.compiled_tasks:+ if tsk.inputs and tsk.inputs[0].name.startswith(name):+ break+ else:+ # no corresponding file, continue+ continue++ # the file foo.cpp could be compiled for a static and a shared library - hence the %number in the name+ cxx_node = x.parent.get_bld().make_node(x.name.replace('.', '_') + '_%d_moc.cpp' % self.generator.idx)+ if cxx_node in cache:+ continue+ cache[cxx_node] = self++ tsk = Task.classes['moc'](env=self.env, generator=self.generator)+ tsk.set_inputs(x)+ tsk.set_outputs(cxx_node)++ if x.name.endswith('.cpp'):+ # moc is trying to be too smart but it is too dumb:+ # why forcing the #include when Q_OBJECT is in the cpp file?+ gen = self.generator.bld.producer+ gen.outstanding.insert(0, tsk)+ gen.total += 1+ self.set_run_after(tsk)+ else:+ cxxtsk = Task.classes['cxx'](env=self.env, generator=self.generator)+ cxxtsk.set_inputs(tsk.outputs)+ cxxtsk.set_outputs(cxx_node.change_ext('.o'))+ cxxtsk.set_run_after(tsk)++ try:+ self.more_tasks.extend([tsk, cxxtsk])+ except AttributeError:+ self.more_tasks = [tsk, cxxtsk]++ try:+ link = self.generator.link_task+ except:+ pass+ else:+ link.set_run_after(cxxtsk)+ link.inputs.extend(cxxtsk.outputs)++ self.moc_done = True++ for t in self.run_after:+ if not t.hasrun:+ return Task.ASK_LATER++ return ret+new file mode 100644@@ -0,0 +1,81 @@+#! /usr/bin/env python+# Thomas Nagy, 2011++# Try to cancel the tasks that cannot run with the option -k when an error occurs:+# 1 direct file dependencies+# 2 tasks listed in the before/after/ext_in/ext_out attributes++from waflib import Task, Runner++Task.CANCELED = 4++def cancel_next(self, tsk):+ if not isinstance(tsk, Task.TaskBase):+ return+ if tsk.hasrun >= Task.SKIPPED:+ # normal execution, no need to do anything here+ return++ try:+ canceled_tasks, canceled_nodes = self.canceled_tasks, self.canceled_nodes+ except AttributeError:+ canceled_tasks = self.canceled_tasks = set([])+ canceled_nodes = self.canceled_nodes = set([])++ try:+ canceled_nodes.update(tsk.outputs)+ except AttributeError:+ pass++ try:+ canceled_tasks.add(tsk)+ except AttributeError:+ pass++def get_out(self):+ tsk = self.out.get()+ if not self.stop:+ self.add_more_tasks(tsk)+ self.count -= 1+ self.dirty = True+ self.cancel_next(tsk) # new code++def error_handler(self, tsk):+ if not self.bld.keep:+ self.stop = True+ self.error.append(tsk)+ self.cancel_next(tsk) # new code++Runner.Parallel.cancel_next = cancel_next+Runner.Parallel.get_out = get_out+Runner.Parallel.error_handler = error_handler++def get_next_task(self):+ tsk = self.get_next_task_smart_continue()+ if not tsk:+ return tsk++ try:+ canceled_tasks, canceled_nodes = self.canceled_tasks, self.canceled_nodes+ except AttributeError:+ pass+ else:+ # look in the tasks that this one is waiting on+ # if one of them was canceled, cancel this one too+ for x in tsk.run_after:+ if x in canceled_tasks:+ tsk.hasrun = Task.CANCELED+ self.cancel_next(tsk)+ break+ else:+ # so far so good, now consider the nodes+ for x in getattr(tsk, 'inputs', []) + getattr(tsk, 'deps', []):+ if x in canceled_nodes:+ tsk.hasrun = Task.CANCELED+ self.cancel_next(tsk)+ break+ return tsk++Runner.Parallel.get_next_task_smart_continue = Runner.Parallel.get_next_task+Runner.Parallel.get_next_task = get_next_task+new file mode 100644@@ -0,0 +1,74 @@+#! /usr/bin/env python+# per rosengren 2011++from waflib.TaskGen import feature, after_method+from waflib.Task import Task, always_run+from os.path import basename, isabs+from os import tmpfile, linesep++def options(opt):+ grp = opt.add_option_group('Softlink Libraries Options')+ grp.add_option('--exclude', default='/usr/lib,/lib', help='No symbolic links are created for libs within [%default]')++def configure(cnf):+ cnf.find_program('ldd')+ if not cnf.env.SOFTLINK_EXCLUDE:+ cnf.env.SOFTLINK_EXCLUDE = cnf.options.exclude.split(',')++@feature('softlink_libs')+@after_method('process_rule')+def add_finder(self):+ tgt = self.path.find_or_declare(self.target)+ self.create_task('sll_finder', tgt=tgt)+ self.create_task('sll_installer', tgt=tgt)+ always_run(sll_installer)++class sll_finder(Task):+ ext_out = 'softlink_libs'+ def run(self):+ bld = self.generator.bld+ linked=[]+ target_paths = []+ for g in bld.groups:+ for tgen in g:+ # FIXME it might be better to check if there is a link_task (getattr?)+ target_paths += [tgen.path.get_bld().bldpath()]+ linked += [t.outputs[0].bldpath()+ for t in getattr(tgen, 'tasks', [])+ if t.__class__.__name__ in+ ['cprogram', 'cshlib', 'cxxprogram', 'cxxshlib']]+ lib_list = []+ if len(linked):+ cmd = [self.env.LDD] + linked+ # FIXME add DYLD_LIBRARY_PATH+PATH for osx+win32+ ldd_env = {'LD_LIBRARY_PATH': ':'.join(target_paths + self.env.LIBPATH)}+ # FIXME the with syntax will not work in python 2+ with tmpfile() as result:+ self.exec_command(cmd, env=ldd_env, stdout=result)+ result.seek(0)+ for line in result.readlines():+ words = line.split()+ if len(words) < 3 or words[1] != '=>': continue+ lib = words[2]+ if lib == 'not': continue+ if any([lib.startswith(p) for p in+ [bld.bldnode.abspath(), '('] ++ self.env.SOFTLINK_EXCLUDE]):+ continue+ if not isabs(lib):+ continue+ lib_list.append(lib)+ lib_list = sorted(set(lib_list))+ self.outputs[0].write(linesep.join(lib_list + self.env.DYNAMIC_LIBS))+ return 0++class sll_installer(Task):+ ext_in = 'softlink_libs'+ def run(self):+ tgt = self.outputs[0]+ self.generator.bld.install_files('${LIBDIR}', tgt, postpone=False)+ lib_list=tgt.read().split()+ for lib in lib_list:+ self.generator.bld.symlink_as('${LIBDIR}/'+basename(lib), lib, postpone=False)+ return 0+new file mode 100644@@ -0,0 +1,172 @@+#! /usr/bin/env python+# encoding: UTF-8+# Petar Forai+# Thomas Nagy 2008-2010 (ita)++import re+from waflib import Task, Utils, Logs+from waflib.TaskGen import extension, feature, after_method+from waflib.Configure import conf+from waflib.Tools import c_preproc++"""+tasks have to be added dynamically:+- swig interface files may be created at runtime+- the module name may be unknown in advance+"""++SWIG_EXTS = ['.swig', '.i']++re_module = re.compile('%module(?:\s*\(.*\))?\s+(.+)', re.M)++re_1 = re.compile(r'^%module.*?\s+([\w]+)\s*?$', re.M)+re_2 = re.compile('%include "(.*)"', re.M)+re_3 = re.compile('#include "(.*)"', re.M)++class swig(Task.Task):+ color = 'BLUE'+ run_str = '${SWIG} ${SWIGFLAGS} ${SWIGPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${SRC}'+ ext_out = ['.h'] # might produce .h files although it is not mandatory++ def runnable_status(self):+ for t in self.run_after:+ if not t.hasrun:+ return Task.ASK_LATER++ if not getattr(self, 'init_outputs', None):+ self.init_outputs = True+ if not getattr(self, 'module', None):+ # search the module name+ txt = self.inputs[0].read()+ m = re_module.search(txt)+ if not m:+ raise ValueError("could not find the swig module name")+ self.module = m.group(1)++ swig_c(self)++ # add the language-specific output files as nodes+ # call funs in the dict swig_langs+ for x in self.env['SWIGFLAGS']:+ # obtain the language+ x = x[1:]+ try:+ fun = swig_langs[x]+ except KeyError:+ pass+ else:+ fun(self)++ return super(swig, self).runnable_status()++ def scan(self):+ "scan for swig dependencies, climb the .i files"+ env = self.env++ lst_src = []++ seen = []+ to_see = [self.inputs[0]]++ while to_see:+ node = to_see.pop(0)+ if node in seen:+ continue+ seen.append(node)+ lst_src.append(node)++ # read the file+ code = node.read()+ code = c_preproc.re_nl.sub('', code)+ code = c_preproc.re_cpp.sub(c_preproc.repl, code)++ # find .i files and project headers+ names = re_2.findall(code) + re_3.findall(code)+ for n in names:+ for d in self.generator.includes_nodes + [node.parent]:+ u = d.find_resource(n)+ if u:+ to_see.append(u)+ break+ else:+ Logs.warn('could not find %r' % n)++ return (lst_src, [])++# provide additional language processing+swig_langs = {}+def swigf(fun):+ swig_langs[fun.__name__.replace('swig_', '')] = fun+swig.swigf = swigf++def swig_c(self):+ ext = '.swigwrap_%d.c' % self.generator.idx+ flags = self.env['SWIGFLAGS']+ if '-c++' in flags:+ ext += 'xx'+ out_node = self.inputs[0].parent.find_or_declare(self.module + ext)++ if '-c++' in flags:+ c_tsk = self.generator.cxx_hook(out_node)+ else:+ c_tsk = self.generator.c_hook(out_node)++ c_tsk.set_run_after(self)++ ge = self.generator.bld.producer+ ge.outstanding.insert(0, c_tsk)+ ge.total += 1++ try:+ ltask = self.generator.link_task+ except AttributeError:+ pass+ else:+ ltask.set_run_after(c_tsk)+ ltask.inputs.append(c_tsk.outputs[0])++ self.outputs.append(out_node)++ if not '-o' in self.env['SWIGFLAGS']:+ self.env.append_value('SWIGFLAGS', ['-o', self.outputs[0].abspath()])++@swigf+def swig_python(tsk):+ tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.py'))++@swigf+def swig_ocaml(tsk):+ tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.ml'))+ tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.mli'))++@extension(*SWIG_EXTS)+def i_file(self, node):+ # the task instance+ tsk = self.create_task('swig')+ tsk.set_inputs(node)+ tsk.module = getattr(self, 'swig_module', None)++ flags = self.to_list(getattr(self, 'swig_flags', []))+ tsk.env.append_value('SWIGFLAGS', flags)++ # looks like this is causing problems+ #if not '-outdir' in flags:+ # tsk.env.append_value('SWIGFLAGS', ['-outdir', node.parent.abspath()])++@conf+def check_swig_version(self):+ """Check for a minimum swig version like conf.check_swig_version('1.3.28')+ or conf.check_swig_version((1,3,28)) """+ reg_swig = re.compile(r'SWIG Version\s(.*)', re.M)+ swig_out = self.cmd_and_log('%s -version' % self.env['SWIG'])++ swigver = tuple([int(s) for s in reg_swig.findall(swig_out)[0].split('.')])+ self.env['SWIG_VERSION'] = swigver+ msg = 'Checking for swig version'+ self.msg(msg, '.'.join(map(str, swigver)))+ return swigver++def configure(conf):+ swig = conf.find_program('swig', var='SWIG')+ conf.env.SWIGPATH_ST = '-I%s'+new file mode 100644@@ -0,0 +1,71 @@+#! /usr/bin/env python+# encoding: utf-8++"""+this tool supports the export_symbols_regex to export the symbols in a shared library.+by default, all symbols are exported by gcc, and nothing by msvc.+to use the tool, do something like:++def build(ctx):+ ctx(features='c cshlib syms', source='a.c b.c', export_symbols_regex='mylib_.*', target='testlib')++only the symbols starting with 'mylib_' will be exported.+"""++import re+from waflib.Context import STDOUT+from waflib.Task import Task+from waflib.Errors import WafError+from waflib.TaskGen import feature, after_method++class gen_sym(Task):+ def run(self):+ obj = self.inputs[0]+ if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):+ re_nm = re.compile(r'External\s+\|\s+_(' + self.generator.export_symbols_regex + r')\b')+ cmd = ['dumpbin', '/symbols', obj.abspath()]+ else:+ if self.env.DEST_BINFMT == 'pe': #gcc uses nm, and has a preceding _ on windows+ re_nm = re.compile(r'T\s+_(' + self.generator.export_symbols_regex + r')\b')+ else:+ re_nm = re.compile(r'T\s+(' + self.generator.export_symbols_regex + r')\b')+ cmd = ['nm', '-g', obj.abspath()]+ syms = re_nm.findall(self.generator.bld.cmd_and_log(cmd, quiet=STDOUT))+ self.outputs[0].write('%r' % syms)++class compile_sym(Task):+ def run(self):+ syms = {}+ for x in self.inputs:+ slist = eval(x.read())+ for s in slist:+ syms[s] = 1+ lsyms = syms.keys()+ lsyms.sort()+ if self.env.DEST_BINFMT == 'pe':+ self.outputs[0].write('EXPORTS\n' + '\n'.join(lsyms))+ elif self.env.DEST_BINFMT == 'elf':+ self.outputs[0].write('{ global:\n' + ';\n'.join(lsyms) + ";\nlocal: *; };\n")+ else:+ raise WafError('NotImplemented')++@feature('syms')+@after_method('process_source', 'process_use', 'apply_link', 'process_uselib_local')+def do_the_symbol_stuff(self):+ ins = [x.outputs[0] for x in self.compiled_tasks]+ self.gen_sym_tasks = [self.create_task('gen_sym', x, x.change_ext('.%d.sym' % self.idx)) for x in ins]++ tsk = self.create_task('compile_sym',+ [x.outputs[0] for x in self.gen_sym_tasks],+ self.path.find_or_declare(getattr(self, 'sym_filename', self.target + '.def')))+ self.link_task.set_run_after(tsk)+ self.link_task.dep_nodes = [tsk.outputs[0]]+ if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):+ self.link_task.env.append_value('LINKFLAGS', ['/def:' + tsk.outputs[0].bldpath()])+ elif self.env.DEST_BINFMT == 'pe': #gcc on windows takes *.def as an additional input+ self.link_task.inputs.append(tsk.outputs[0])+ elif self.env.DEST_BINFMT == 'elf':+ self.link_task.env.append_value('LINKFLAGS', ['-Wl,-version-script', '-Wl,' + tsk.outputs[0].bldpath()])+ else:+ raise WafError('NotImplemented')+new file mode 100644@@ -0,0 +1,9 @@+#! /usr/bin/env python+# encoding: utf-8++"""+This tool is obsolete, the sync_exec feature is now the default+"""++pass+new file mode 100644@@ -0,0 +1,306 @@+#!/usr/bin/env python+# encoding: utf-8++# Texas Instruments code generator support (experimental)+# When reporting issues, please directly assign the bug to the maintainer.++__author__ = __maintainer__ = "Jérôme Carretero <cJ-waf@zougloub.eu>"+__copyright__ = "Jérôme Carretero, 2012"++"""+TI cgt6x is a compiler suite for TI DSPs.++The toolchain does pretty weird things, and I'm sure I'm missing some of them.+But still, the tool saves time.++What this tool does is:++- create a TI compiler environment+- create TI compiler features, to handle some specifics about this compiler+ It has a few idiosyncracies, such as not giving the liberty of the .o file names+- automatically activate them when using the TI compiler+- handle the tconf tool+ The tool ++TODO:++- the set_platform_flags() function is not nice+- more tests+- broaden tool scope, if needed++"""++import os, re++from waflib import Configure, Options, Utils, Task, TaskGen+from waflib.Tools import c, ccroot, c_preproc+from waflib.Configure import conf+from waflib.TaskGen import feature, before_method, taskgen_method+from waflib.Tools.ccroot import link_task, stlink_task+from waflib.Tools.c import cprogram++opj = os.path.join++@conf+def find_ticc(conf):+ cc = conf.find_program(['cl6x'], var='CC', path_list=opj(getattr(Options.options, 'ti-cgt-dir', ""), 'bin'))+ cc = conf.cmd_to_list(cc)+ conf.env.CC_NAME = 'ticc'+ conf.env.CC = cc++@conf+def find_tild(conf):+ ld = conf.find_program(['lnk6x'], var='LINK_CC', path_list=opj(getattr(Options.options, 'ti-cgt-dir', ""), 'bin'))+ ld = conf.cmd_to_list(ld)+ conf.env.LINK_CC_NAME = 'tild'+ conf.env.LINK_CC = ld++@conf+def find_tiar(conf):+ ar = conf.find_program(['ar6x'], var='AR', path_list=opj(getattr(Options.options, 'ti-cgt-dir', ""), 'bin'))+ ar = conf.cmd_to_list(ar)+ conf.env.AR = ar+ conf.env.AR_NAME = 'tiar'+ conf.env.ARFLAGS = 'qru'++@conf+def ticc_common_flags(conf):+ v = conf.env++ if not v['LINK_CC']: v['LINK_CC'] = v['CC']+ v['CCLNK_SRC_F'] = []+ v['CCLNK_TGT_F'] = ['-o']+ v['CPPPATH_ST'] = '-I%s'+ v['DEFINES_ST'] = '-d%s'++ v['LIB_ST'] = '-l%s' # template for adding libs+ v['LIBPATH_ST'] = '-i%s' # template for adding libpaths+ v['STLIB_ST'] = '-l=%s.lib'+ v['STLIBPATH_ST'] = '-i%s'++ # program+ v['cprogram_PATTERN'] = '%s.out'++ # static lib+ #v['LINKFLAGS_cstlib'] = ['-Wl,-Bstatic']+ v['cstlib_PATTERN'] = '%s.lib'++def configure(conf):+ v = conf.env+ v.TI_CGT_DIR = getattr(Options.options, 'ti-cgt-dir', "")+ v.TI_DSPLINK_DIR = getattr(Options.options, 'ti-dsplink-dir', "")+ v.TI_BIOSUTILS_DIR = getattr(Options.options, 'ti-biosutils-dir', "")+ v.TI_DSPBIOS_DIR = getattr(Options.options, 'ti-dspbios-dir', "")+ v.TI_XDCTOOLS_DIR = getattr(Options.options, 'ti-xdctools-dir', "")+ conf.find_ticc()+ conf.find_tiar()+ conf.find_tild()+ conf.ticc_common_flags()+ conf.cc_load_tools()+ conf.cc_add_flags()+ conf.link_add_flags()+ v.TCONF = conf.cmd_to_list(conf.find_program(['tconf'], var='TCONF', path_list=v.TI_XDCTOOLS_DIR))+ + conf.env.TCONF_INCLUDES += [+ opj(conf.env.TI_DSPBIOS_DIR, 'packages'),+ ]+ + conf.env.INCLUDES += [+ opj(conf.env.TI_CGT_DIR, 'include'),+ ]+ + conf.env.LIBPATH += [+ opj(conf.env.TI_CGT_DIR, "lib"),+ ]++ conf.env.INCLUDES_DSPBIOS += [+ opj(conf.env.TI_DSPBIOS_DIR, 'packages', 'ti', 'bios', 'include'),+ ]+ + conf.env.LIBPATH_DSPBIOS += [+ opj(conf.env.TI_DSPBIOS_DIR, 'packages', 'ti', 'bios', 'lib'),+ ]++ conf.env.INCLUDES_DSPLINK += [+ opj(conf.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc'),+ ]+ +@conf+def ti_set_debug(cfg, debug=1):+ """+ Sets debug flags for the compiler.++ TODO:+ - for each TI CFLAG/INCLUDES/LINKFLAGS/LIBPATH replace RELEASE by DEBUG+ - -g --no_compress+ """+ if debug:+ cfg.env.CFLAGS += "-d_DEBUG -dDEBUG -dDDSP_DEBUG".split()++@conf+def ti_dsplink_set_platform_flags(cfg, splat, dsp, dspbios_ver, board):+ """+ Sets the INCLUDES, LINKFLAGS for DSPLINK and TCONF_INCLUDES+ For the specific hardware.++ Assumes that DSPLINK was built in its own folder.++ :param splat: short platform name (eg. OMAPL138)+ :param dsp: DSP name (eg. 674X)+ :param dspbios_ver: string identifying DspBios version (eg. 5.XX)+ :param board: board name (eg. OMAPL138GEM)++ """+ d1 = opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc', 'DspBios', dspbios_ver)+ d = opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc', 'DspBios', dspbios_ver, board)+ cfg.env.TCONF_INCLUDES += [d1, d]+ cfg.env.INCLUDES_DSPLINK += [+ opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc', dsp),+ d,+ ]+ + cfg.env.LINKFLAGS_DSPLINK += [+ opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'export', 'BIN', 'DspBios', splat, board+'_0', 'RELEASE', 'dsplink%s.lib' % x)+ for x in ['', 'pool', 'mpcs', 'mplist', 'msg', 'data', 'notify', 'ringio']+ ]+++def options(opt):+ opt.add_option('--with-ti-cgt', type='string', dest='ti-cgt-dir', help = 'Specify alternate cgt root folder', default="")+ opt.add_option('--with-ti-biosutils', type='string', dest='ti-biosutils-dir', help = 'Specify alternate biosutils folder', default="")+ opt.add_option('--with-ti-dspbios', type='string', dest='ti-dspbios-dir', help = 'Specify alternate dspbios folder', default="")+ opt.add_option('--with-ti-dsplink', type='string', dest='ti-dsplink-dir', help = 'Specify alternate dsplink folder', default="")+ opt.add_option('--with-ti-xdctools', type='string', dest='ti-xdctools-dir', help = 'Specify alternate xdctools folder', default="")++class ti_cprogram(cprogram):+ """+ Link object files into a c program+ + Changes:++ - the linked executable to have a relative path (because we can)+ - put the LIBPATH first+ """+ run_str = '${LINK_CC} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB} ${LINKFLAGS} ${CCLNK_SRC_F}${SRC} ${CCLNK_TGT_F}${TGT[0].bldpath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} '++@feature("c")+@before_method('apply_link')+def use_ti_cprogram(self):+ """+ Automatically uses ti_cprogram link process+ """+ if 'cprogram' in self.features and self.env.CC_NAME == 'ticc':+ self.features.insert(0, "ti_cprogram")++class ti_c(Task.Task):+ """+ Compile task for the TI codegen compiler++ This compiler does not allow specifying the output file name, only the output path.++ """+ "Compile C files into object files"+ run_str = '${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${CPPFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${SRC} -c ${OUT}'+ vars = ['CCDEPS'] # unused variable to depend on, just in case+ ext_in = ['.h'] # set the build order easily by using ext_out=['.h']+ scan = c_preproc.scan++def create_compiled_task(self, name, node):+ """+ Overrides ccroot.create_compiled_task to support ti_c+ """+ out = '%s' % (node.change_ext('.obj').name)+ if self.env.CC_NAME == 'ticc':+ name = 'ti_c'+ task = self.create_task(name, node, node.parent.find_or_declare(out))+ self.env.OUT = '-fr%s' % (node.parent.get_bld().abspath())+ try:+ self.compiled_tasks.append(task)+ except AttributeError:+ self.compiled_tasks = [task]+ return task++@TaskGen.extension('.c')+def c_hook(self, node):+ "Bind the c file extension to the creation of a :py:class:`waflib.Tools.c.c` instance"+ if self.env.CC_NAME == 'ticc':+ return create_compiled_task(self, 'ti_c', node)+ else:+ return self.create_compiled_task('c', node)+++@feature("ti-tconf")+@before_method('process_source')+def apply_tconf(self):+ sources = [x.get_src() for x in self.to_nodes(self.source, path=self.path.get_src())]+ node = sources[0]+ assert(sources[0].name.endswith(".tcf"))+ if len(sources) > 1:+ assert(sources[1].name.endswith(".cmd"))++ target = getattr(self, 'target', self.source)+ target_node = node.get_bld().parent.find_or_declare(node.name)+ + procid = "%d" % int(getattr(self, 'procid', 0))++ importpaths = []+ includes = Utils.to_list(getattr(self, 'includes', []))+ for x in includes + self.env.TCONF_INCLUDES:+ if x == os.path.abspath(x):+ importpaths.append(x)+ else:+ relpath = self.path.find_node(x).path_from(target_node.parent)+ importpaths.append(relpath)++ task = self.create_task('ti_tconf', sources, target_node.change_ext('.cdb'))+ task.path = self.path+ task.includes = includes+ task.cwd = target_node.parent.abspath()+ task.env = self.env.derive()+ task.env["TCONFSRC"] = node.path_from(target_node.parent)+ task.env["TCONFINC"] = '-Dconfig.importPath=%s' % ";".join(importpaths)+ task.env['TCONFPROGNAME'] = '-Dconfig.programName=%s' % target+ task.env['PROCID'] = procid+ task.outputs = [+ target_node.change_ext("cfg_c.c"),+ target_node.change_ext("cfg.s62"),+ target_node.change_ext("cfg.cmd"),+ ]++ s62task = create_compiled_task(self, 'ti_c', task.outputs[1])+ ctask = create_compiled_task(self, 'ti_c', task.outputs[0])+ ctask.env = self.env.derive()++ self.add_those_o_files(target_node.change_ext("cfg.cmd"))+ if len(sources) > 1:+ self.add_those_o_files(sources[1])+ self.source = []++re_tconf_include = re.compile(r'(?P<type>utils\.importFile)\("(?P<file>.*)"\)',re.M)+class ti_tconf(Task.Task):+ run_str = '${TCONF} ${TCONFINC} ${TCONFPROGNAME} ${TCONFSRC} ${PROCID}'+ color = 'PINK'++ def scan(self):+ includes = Utils.to_list(getattr(self, 'includes', []))++ def deps(node):+ nodes, names = [], []+ if node:+ code = Utils.readf(node.abspath())+ for match in re_tconf_include.finditer(code):+ path = match.group('file')+ if path:+ for x in includes:+ filename = opj(x, path)+ fi = self.path.find_resource(filename)+ if fi:+ subnodes, subnames = deps(fi)+ nodes += subnodes+ names += subnames+ nodes.append(fi)+ names.append(path)+ break+ return nodes, names+ return deps(self.inputs[0])+new file mode 100644@@ -0,0 +1,129 @@+#! /usr/bin/env python+# encoding: UTF-8+# Nicolas Joseph 2009++"""+ported from waf 1.5:+TODO: tabs vs spaces+"""++from waflib import Task, Utils, Node, Errors, Logs+from waflib.TaskGen import feature, extension, after_method++VALADOC_STR = '${VALADOC}'++class valadoc(Task.Task):+ vars = ['VALADOC', 'VALADOCFLAGS']+ color = 'BLUE'+ after = ['cprogram', 'cstlib', 'cshlib', 'cxxprogram', 'cxxstlib', 'cxxshlib']+ quiet = True # no outputs .. this is weird++ def __init__(self, *k, **kw):+ Task.Task.__init__(self, *k, **kw)+ self.output_dir = ''+ self.doclet = ''+ self.package_name = ''+ self.package_version = ''+ self.files = []+ self.vapi_dirs = []+ self.protected = True+ self.private = False+ self.inherit = False+ self.deps = False+ self.enable_non_null_experimental = False+ self.force = False++ def run(self):+ if not self.env['VALADOCFLAGS']:+ self.env['VALADOCFLAGS'] = ''+ cmd = [Utils.subst_vars(VALADOC_STR, self.env)]+ cmd.append ('-o %s' % self.output_dir)+ if getattr(self, 'doclet', None):+ cmd.append ('--doclet %s' % self.doclet)+ cmd.append ('--package-name %s' % self.package_name)+ if getattr(self, 'package_version', None):+ cmd.append ('--package-version %s' % self.package_version)+ if getattr(self, 'packages', None):+ for package in self.packages:+ cmd.append ('--pkg %s' % package)+ if getattr(self, 'vapi_dirs', None):+ for vapi_dir in self.vapi_dirs:+ cmd.append ('--vapidir %s' % vapi_dir)+ if not getattr(self, 'protected', None):+ cmd.append ('--no-protected')+ if getattr(self, 'private', None):+ cmd.append ('--private')+ if getattr(self, 'inherit', None):+ cmd.append ('--inherit')+ if getattr(self, 'deps', None):+ cmd.append ('--deps')+ if getattr(self, 'enable_non_null_experimental', None):+ cmd.append ('--enable-non-null-experimental')+ if getattr(self, 'force', None):+ cmd.append ('--force')+ cmd.append (' '.join ([x.abspath() for x in self.files]))+ return self.generator.bld.exec_command(' '.join(cmd))++@feature('valadoc')+def process_valadoc(self):+ """+ Generate API documentation from Vala source code with valadoc++ doc = bld(+ features = 'valadoc',+ output_dir = '../doc/html',+ package_name = 'vala-gtk-example',+ package_version = '1.0.0',+ packages = 'gtk+-2.0',+ vapi_dirs = '../vapi',+ force = True+ )++ path = bld.path.find_dir ('../src')+ doc.files = path.ant_glob (incl='**/*.vala')+ """++ task = self.create_task('valadoc')+ if getattr(self, 'output_dir', None):+ task.output_dir = self.path.find_or_declare(self.output_dir).abspath()+ else:+ Errors.WafError('no output directory')+ if getattr(self, 'doclet', None):+ task.doclet = self.doclet+ else:+ Errors.WafError('no doclet directory')+ if getattr(self, 'package_name', None):+ task.package_name = self.package_name+ else:+ Errors.WafError('no package name')+ if getattr(self, 'package_version', None):+ task.package_version = self.package_version+ if getattr(self, 'packages', None):+ task.packages = Utils.to_list(self.packages)+ if getattr(self, 'vapi_dirs', None):+ vapi_dirs = Utils.to_list(self.vapi_dirs)+ for vapi_dir in vapi_dirs:+ try:+ task.vapi_dirs.append(self.path.find_dir(vapi_dir).abspath())+ except AttributeError:+ Logs.warn("Unable to locate Vala API directory: '%s'" % vapi_dir)+ if getattr(self, 'files', None):+ task.files = self.files+ else:+ Errors.WafError('no input file')+ if getattr(self, 'protected', None):+ task.protected = self.protected+ if getattr(self, 'private', None):+ task.private = self.private+ if getattr(self, 'inherit', None):+ task.inherit = self.inherit+ if getattr(self, 'deps', None):+ task.deps = self.deps+ if getattr(self, 'enable_non_null_experimental', None):+ task.enable_non_null_experimental = self.enable_non_null_experimental+ if getattr(self, 'force', None):+ task.force = self.force++def configure(conf):+ conf.find_program('valadoc', errmsg='You must install valadoc <http://live.gnome.org/Valadoc> for generate the API documentation')+new file mode 100644@@ -0,0 +1,73 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010 (ita)++"""+This tool modifies the task signature scheme to store and obtain+information about the task execution (why it must run, etc)::++ def configure(conf):+ conf.load('why')++After adding the tool, a full rebuild is necessary.+"""++from waflib import Task, Utils, Logs, Errors++def signature(self):+ # compute the result one time, and suppose the scan_signature will give the good result+ try: return self.cache_sig+ except AttributeError: pass++ self.m = Utils.md5()+ self.m.update(self.hcode.encode())+ id_sig = self.m.digest()++ # explicit deps+ self.sig_explicit_deps()+ exp_sig = self.m.digest()++ # env vars+ self.sig_vars()+ var_sig = self.m.digest()++ # implicit deps / scanner results+ if self.scan:+ try:+ self.sig_implicit_deps()+ except Errors.TaskRescan:+ return self.signature()++ ret = self.cache_sig = self.m.digest() + id_sig + exp_sig + var_sig+ return ret+++Task.Task.signature = signature++old = Task.Task.runnable_status+def runnable_status(self):+ ret = old(self)+ if ret == Task.RUN_ME:+ try:+ old_sigs = self.generator.bld.task_sigs[self.uid()]+ except:+ Logs.debug("task: task must run as no previous signature exists")+ else:+ new_sigs = self.cache_sig+ def v(x):+ return Utils.to_hex(x)++ Logs.debug("Task %r" % self)+ msgs = ['Task must run', '* Task code', '* Source file or manual dependency', '* Configuration data variable']+ tmp = 'task: -> %s: %s %s'+ for x in range(len(msgs)):+ l = len(Utils.SIG_NIL)+ a = new_sigs[x*l : (x+1)*l]+ b = old_sigs[x*l : (x+1)*l]+ if (a != b):+ Logs.debug(tmp % (msgs[x].ljust(35), v(a), v(b)))+ if x > 0:+ break+ return ret+Task.Task.runnable_status = runnable_status+new file mode 100644@@ -0,0 +1,178 @@+#! /usr/bin/env python+# encoding: utf-8++"""+Windows-specific optimizations++This module can help reducing the overhead of listing files on windows (more than 10000 files).+"""++import os+try: import cPickle+except: import pickle as cPickle+from waflib import Utils, Build, Context, Node, Logs++try:+ TP = '%s\\*'.decode('ascii')+except AttributeError:+ TP = '%s\\*'++if Utils.is_win32:+ from waflib.extras import md5_tstamp+ import ctypes, ctypes.wintypes++ FindFirstFile = ctypes.windll.kernel32.FindFirstFileW+ FindNextFile = ctypes.windll.kernel32.FindNextFileW+ FindClose = ctypes.windll.kernel32.FindClose+ FILE_ATTRIBUTE_DIRECTORY = 0x10+ INVALID_HANDLE_VALUE = -1+ UPPER_FOLDERS = ('.', '..')+ try:+ UPPER_FOLDERS = [unicode(x) for x in UPPER_FOLDERS]+ except NameError:+ pass++ def cached_hash_file(self):+ try:+ cache = self.ctx.cache_listdir_cache_hash_file+ except AttributeError:+ cache = self.ctx.cache_listdir_cache_hash_file = {}++ if id(self.parent) in cache:+ try:+ t = cache[id(self.parent)][self.name]+ except KeyError:+ raise IOError('Not a file')+ else:+ # an opportunity to list the files and the timestamps at once+ findData = ctypes.wintypes.WIN32_FIND_DATAW()+ find = FindFirstFile(TP % self.parent.abspath(), ctypes.byref(findData))++ if find == INVALID_HANDLE_VALUE:+ cache[id(self.parent)] = {}+ raise IOError('Not a file')++ cache[id(self.parent)] = lst_files = {}+ try:+ while True:+ if findData.cFileName not in UPPER_FOLDERS:+ thatsadir = findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY+ if not thatsadir:+ ts = findData.ftLastWriteTime+ d = (ts.dwLowDateTime << 32) | ts.dwHighDateTime+ lst_files[str(findData.cFileName)] = d+ if not FindNextFile(find, ctypes.byref(findData)):+ break+ except Exception as e:+ cache[id(self.parent)] = {}+ raise IOError('Not a file')+ finally:+ FindClose(find)+ t = lst_files[self.name]++ fname = self.abspath()+ if fname in Build.hashes_md5_tstamp:+ if Build.hashes_md5_tstamp[fname][0] == t:+ return Build.hashes_md5_tstamp[fname][1]++ try:+ fd = os.open(fname, os.O_BINARY | os.O_RDONLY | os.O_NOINHERIT)+ except OSError:+ raise IOError('Cannot read from %r' % fname)+ f = os.fdopen(fd, 'rb')+ m = Utils.md5()+ rb = 1+ try:+ while rb:+ rb = f.read(200000)+ m.update(rb)+ finally:+ f.close()++ # ensure that the cache is overwritten+ Build.hashes_md5_tstamp[fname] = (t, m.digest())+ return m.digest()+ Node.Node.cached_hash_file = cached_hash_file++ def get_bld_sig_win32(self):+ try:+ return self.ctx.hash_cache[id(self)]+ except KeyError:+ pass+ except AttributeError:+ self.ctx.hash_cache = {}++ if not self.is_bld():+ if self.is_child_of(self.ctx.srcnode):+ self.sig = self.cached_hash_file()+ else:+ self.sig = Utils.h_file(self.abspath())+ self.ctx.hash_cache[id(self)] = ret = self.sig+ return ret+ Node.Node.get_bld_sig = get_bld_sig_win32++ def isfile_cached(self):+ # optimize for nt.stat calls, assuming there are many files for few folders+ try:+ cache = self.__class__.cache_isfile_cache+ except AttributeError:+ cache = self.__class__.cache_isfile_cache = {}++ try:+ c1 = cache[id(self.parent)]+ except KeyError:+ c1 = cache[id(self.parent)] = []++ curpath = self.parent.abspath()+ findData = ctypes.wintypes.WIN32_FIND_DATAW()+ find = FindFirstFile(TP % curpath, ctypes.byref(findData))++ if find == INVALID_HANDLE_VALUE:+ Logs.error("invalid win32 handle isfile_cached %r" % self.abspath())+ return os.path.isfile(self.abspath())++ try:+ while True:+ if findData.cFileName not in UPPER_FOLDERS:+ thatsadir = findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY+ if not thatsadir:+ c1.append(str(findData.cFileName))+ if not FindNextFile(find, ctypes.byref(findData)):+ break+ except Exception as e:+ Logs.error('exception while listing a folder %r %r' % (self.abspath(), e))+ return os.path.isfile(self.abspath())+ finally:+ FindClose(find)+ return self.name in c1+ Node.Node.isfile_cached = isfile_cached++ def find_or_declare_win32(self, lst):+ # assuming that "find_or_declare" is called before the build starts, remove the calls to os.path.isfile+ if isinstance(lst, str):+ lst = [x for x in Node.split_path(lst) if x and x != '.']++ node = self.get_bld().search(lst)+ if node:+ if not node.isfile_cached():+ node.sig = None+ try:+ node.parent.mkdir()+ except:+ pass+ return node+ self = self.get_src()+ node = self.find_node(lst)+ if node:+ if not node.isfile_cached():+ node.sig = None+ try:+ node.parent.mkdir()+ except:+ pass+ return node+ node = self.get_bld().make_node(lst)+ node.parent.mkdir()+ return node+ Node.Node.find_or_declare = find_or_declare_win32+new file mode 100644@@ -0,0 +1,312 @@+#! /usr/bin/env python+# encoding: utf-8+# XCode 3/XCode 4 generator for Waf+# Nicolas Mercier 2011++"""+Usage:++def options(opt):+ opt.load('xcode')++$ waf configure xcode+"""++# TODO: support iOS projects++from waflib import Context, TaskGen, Build, Utils+import os, sys, random, time++HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)'++MAP_EXT = {+ '.h' : "sourcecode.c.h",++ '.hh': "sourcecode.cpp.h",+ '.inl': "sourcecode.cpp.h",+ '.hpp': "sourcecode.cpp.h",++ '.c': "sourcecode.c.c",++ '.m': "sourcecode.c.objc",++ '.mm': "sourcecode.cpp.objcpp",++ '.cc': "sourcecode.cpp.cpp",++ '.cpp': "sourcecode.cpp.cpp",+ '.C': "sourcecode.cpp.cpp",+ '.cxx': "sourcecode.cpp.cpp",+ '.c++': "sourcecode.cpp.cpp",++ '.l': "sourcecode.lex", # luthor+ '.ll': "sourcecode.lex",++ '.y': "sourcecode.yacc",+ '.yy': "sourcecode.yacc",++ '.plist': "text.plist.xml",+ ".nib": "wrapper.nib",+ ".xib": "text.xib",+}+++part1 = 0+part2 = 10000+part3 = 0+id = 562000999+def newid():+ global id+ id = id + 1+ return "%04X%04X%04X%012d" % (0, 10000, 0, id)++class XCodeNode:+ def __init__(self):+ self._id = newid()++ def tostring(self, value):+ if isinstance(value, dict):+ result = "{\n"+ for k,v in value.items():+ result = result + "\t\t\t%s = %s;\n" % (k, self.tostring(v))+ result = result + "\t\t}"+ return result+ elif isinstance(value, str):+ return "\"%s\"" % value+ elif isinstance(value, list):+ result = "(\n"+ for i in value:+ result = result + "\t\t\t%s,\n" % self.tostring(i)+ result = result + "\t\t)"+ return result+ elif isinstance(value, XCodeNode):+ return value._id+ else:+ return str(value)++ def write_recursive(self, value, file):+ if isinstance(value, dict):+ for k,v in value.items():+ self.write_recursive(v, file)+ elif isinstance(value, list):+ for i in value:+ self.write_recursive(i, file)+ elif isinstance(value, XCodeNode):+ value.write(file)++ def write(self, file):+ for attribute,value in self.__dict__.items():+ if attribute[0] != '_':+ self.write_recursive(value, file)++ w = file.write+ w("\t%s = {\n" % self._id)+ w("\t\tisa = %s;\n" % self.__class__.__name__)+ for attribute,value in self.__dict__.items():+ if attribute[0] != '_':+ w("\t\t%s = %s;\n" % (attribute, self.tostring(value)))+ w("\t};\n\n")++++# Configurations+class XCBuildConfiguration(XCodeNode):+ def __init__(self, name, settings = {}, env=None):+ XCodeNode.__init__(self)+ self.baseConfigurationReference = ""+ self.buildSettings = settings+ self.name = name+ if env and env.ARCH:+ settings['ARCHS'] = " ".join(env.ARCH)+++class XCConfigurationList(XCodeNode):+ def __init__(self, settings):+ XCodeNode.__init__(self)+ self.buildConfigurations = settings+ self.defaultConfigurationIsVisible = 0+ self.defaultConfigurationName = settings and settings[0].name or ""++# Group/Files+class PBXFileReference(XCodeNode):+ def __init__(self, name, path, filetype = '', sourcetree = "SOURCE_ROOT"):+ XCodeNode.__init__(self)+ self.fileEncoding = 4+ if not filetype:+ _, ext = os.path.splitext(name)+ filetype = MAP_EXT.get(ext, 'text')+ self.lastKnownFileType = filetype+ self.name = name+ self.path = path+ self.sourceTree = sourcetree++class PBXGroup(XCodeNode):+ def __init__(self, name, sourcetree = "<group>"):+ XCodeNode.__init__(self)+ self.children = []+ self.name = name+ self.sourceTree = sourcetree++ def add(self, root, sources):+ folders = {}+ def folder(n):+ if n == root:+ return self+ try:+ return folders[n]+ except KeyError:+ f = PBXGroup(n.name)+ p = folder(n.parent)+ folders[n] = f+ p.children.append(f)+ return f+ for s in sources:+ f = folder(s.parent)+ source = PBXFileReference(s.name, s.abspath())+ f.children.append(source)+++# Targets+class PBXLegacyTarget(XCodeNode):+ def __init__(self, action, target=''):+ XCodeNode.__init__(self)+ self.buildConfigurationList = XCConfigurationList([XCBuildConfiguration('waf', {})])+ if not target:+ self.buildArgumentsString = "%s %s" % (sys.argv[0], action)+ else:+ self.buildArgumentsString = "%s %s --targets=%s" % (sys.argv[0], action, target)+ self.buildPhases = []+ self.buildToolPath = sys.executable+ self.buildWorkingDirectory = ""+ self.dependencies = []+ self.name = target or action+ self.productName = target or action+ self.passBuildSettingsInEnvironment = 0++class PBXShellScriptBuildPhase(XCodeNode):+ def __init__(self, action, target):+ XCodeNode.__init__(self)+ self.buildActionMask = 2147483647+ self.files = []+ self.inputPaths = []+ self.outputPaths = []+ self.runOnlyForDeploymentPostProcessing = 0+ self.shellPath = "/bin/sh"+ self.shellScript = "%s %s %s --targets=%s" % (sys.executable, sys.argv[0], action, target)++class PBXNativeTarget(XCodeNode):+ def __init__(self, action, target, node, env):+ XCodeNode.__init__(self)+ conf = XCBuildConfiguration('waf', {'PRODUCT_NAME':target, 'CONFIGURATION_BUILD_DIR':node.parent.abspath()}, env)+ self.buildConfigurationList = XCConfigurationList([conf])+ self.buildPhases = [PBXShellScriptBuildPhase(action, target)]+ self.buildRules = []+ self.dependencies = []+ self.name = target+ self.productName = target+ self.productType = "com.apple.product-type.application"+ self.productReference = PBXFileReference(target, node.abspath(), 'wrapper.application', 'BUILT_PRODUCTS_DIR')++# Root project object+class PBXProject(XCodeNode):+ def __init__(self, name, version):+ XCodeNode.__init__(self)+ self.buildConfigurationList = XCConfigurationList([XCBuildConfiguration('waf', {})])+ self.compatibilityVersion = version[0]+ self.hasScannedForEncodings = 1;+ self.mainGroup = PBXGroup(name)+ self.projectRoot = ""+ self.projectDirPath = ""+ self.targets = []+ self._objectVersion = version[1]+ self._output = PBXGroup('out')+ self.mainGroup.children.append(self._output)++ def write(self, file):+ w = file.write+ w("// !$*UTF8*$!\n")+ w("{\n")+ w("\tarchiveVersion = 1;\n")+ w("\tclasses = {\n")+ w("\t};\n")+ w("\tobjectVersion = %d;\n" % self._objectVersion)+ w("\tobjects = {\n\n")++ XCodeNode.write(self, file)++ w("\t};\n")+ w("\trootObject = %s;\n" % self._id)+ w("}\n")++ def add_task_gen(self, tg):+ if not getattr(tg, 'mac_app', False):+ self.targets.append(PBXLegacyTarget('build', tg.name))+ else:+ target = PBXNativeTarget('build', tg.name, tg.link_task.outputs[0].change_ext('.app'), tg.env)+ self.targets.append(target)+ self._output.children.append(target.productReference)++class xcode(Build.BuildContext):+ cmd = 'xcode'+ fun = 'build'++ def collect_source(self, tg):+ source_files = tg.to_nodes(getattr(tg, 'source', []))+ plist_files = tg.to_nodes(getattr(tg, 'mac_plist', []))+ resource_files = [tg.path.find_node(i) for i in Utils.to_list(getattr(tg, 'mac_resources', []))]+ include_dirs = Utils.to_list(getattr(tg, 'includes', [])) + Utils.to_list(getattr(tg, 'export_dirs', []))+ include_files = []+ for x in include_dirs:+ if not isinstance(x, str):+ include_files.append(x)+ continue+ d = tg.path.find_node(x)+ if d:+ lst = [y for y in d.ant_glob(HEADERS_GLOB, flat=False)]+ include_files.extend(lst)++ # remove duplicates+ source = list(set(source_files + plist_files + resource_files + include_files))+ source.sort(key=lambda x: x.abspath())+ return source++ def execute(self):+ """+ Entry point+ """+ self.restore()+ if not self.all_envs:+ self.load_envs()+ self.recurse([self.run_dir])++ appname = getattr(Context.g_module, Context.APPNAME, os.path.basename(self.srcnode.abspath()))+ p = PBXProject(appname, ('Xcode 3.2', 46))++ for g in self.groups:+ for tg in g:+ if not isinstance(tg, TaskGen.task_gen):+ continue++ tg.post()++ features = Utils.to_list(getattr(tg, 'features', ''))++ group = PBXGroup(tg.name)+ group.add(tg.path, self.collect_source(tg))+ p.mainGroup.children.append(group)++ if 'cprogram' or 'cxxprogram' in features:+ p.add_task_gen(tg)+++ # targets that don't produce the executable but that you might want to run+ p.targets.append(PBXLegacyTarget('configure'))+ p.targets.append(PBXLegacyTarget('dist'))+ p.targets.append(PBXLegacyTarget('install'))+ p.targets.append(PBXLegacyTarget('check'))+ node = self.srcnode.make_node('%s.xcodeproj' % appname)+ node.mkdir()+ node = node.make_node('project.pbxproj')+ p.write(open(node.abspath(), 'w'))++new file mode 100644@@ -0,0 +1,71 @@+#!/usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2010 (ita)++"""+burn a book, save a tree+"""++import os+all_modifs = {}++def fixdir(dir):+ """call all the substitution functions on the waf folders"""+ global all_modifs+ for k in all_modifs:+ for v in all_modifs[k]:+ modif(os.path.join(dir, 'waflib'), k, v)++def modif(dir, name, fun):+ """execute a substitution function"""+ if name == '*':+ lst = []+ for y in '. Tools extras'.split():+ for x in os.listdir(os.path.join(dir, y)):+ if x.endswith('.py'):+ lst.append(y + os.sep + x)+ for x in lst:+ modif(dir, x, fun)+ return++ filename = os.path.join(dir, name)+ f = open(filename, 'r')+ try:+ txt = f.read()+ finally:+ f.close()++ txt = fun(txt)++ f = open(filename, 'w')+ try:+ f.write(txt)+ finally:+ f.close()++def subst(*k):+ """register a substitution function"""+ def do_subst(fun):+ global all_modifs+ for x in k:+ try:+ all_modifs[x].append(fun)+ except KeyError:+ all_modifs[x] = [fun]+ return fun+ return do_subst++@subst('*')+def r1(code):+ "utf-8 fixes for python < 2.6"+ code = code.replace('as e:', ',e:')+ code = code.replace(".decode(sys.stdout.encoding or 'iso8859-1')", '')+ code = code.replace('.encode()', '')+ return code++@subst('Runner.py')+def r4(code):+ "generator syntax"+ code = code.replace('next(self.biter)', 'self.biter.next()')+ return code+new file mode 100644@@ -0,0 +1,372 @@+#! /usr/bin/env python+# encoding: utf-8+# Thomas Nagy, 2005-2010++"""+to make a custom waf file use the option --tools++To add a tool that does not exist in the folder compat15, pass an absolute path:+./waf-light --make-waf --tools=compat15,/comp/waf/aba.py --prelude=$'\tfrom waflib.extras import aba\n\taba.foo()'+"""+++VERSION="1.7.6"+APPNAME='waf'+REVISION=''++top = '.'+out = 'build'++demos = ['cpp', 'qt4', 'tex', 'ocaml', 'kde3', 'adv', 'cc', 'idl', 'docbook', 'xmlwaf', 'gnome']+zip_types = ['bz2', 'gz']++PRELUDE = ''++#from tokenize import *+import tokenize++import os, sys, re, io, optparse++from waflib import Utils, Options, Logs+from hashlib import md5++from waflib import Configure+Configure.autoconfig = 1++def sub_file(fname, lst):++ f = open(fname, 'rU')+ try:+ txt = f.read()+ finally:+ f.close()++ for (key, val) in lst:+ re_pat = re.compile(key, re.M)+ txt = re_pat.sub(val, txt)++ f = open(fname, 'w')+ try:+ f.write(txt)+ finally:+ f.close()++def to_bytes(x):+ if sys.hexversion>0x300000f:+ return x.encode()+ return x++print("------> Executing code from the top-level wscript <-----")+def init(ctx):+ if Options.options.setver: # maintainer only (ita)+ ver = Options.options.setver+ hexver = Utils.num2ver(ver)+ hexver = '0x%x'%hexver+ sub_file('wscript', (('^VERSION=(.*)', 'VERSION="%s"' % ver), ))+ sub_file('waf-light', (('^VERSION=(.*)', 'VERSION="%s"' % ver), ))++ pats = []+ pats.append(('^WAFVERSION=(.*)', 'WAFVERSION="%s"' % ver))+ pats.append(('^HEXVERSION(.*)', 'HEXVERSION=%s' % hexver))++ try:+ rev = ctx.cmd_and_log("git rev-parse HEAD").strip()+ pats.append(('^WAFREVISION(.*)', 'WAFREVISION="%s"' % rev))+ except Exception:+ pass++ sub_file('waflib/Context.py', pats)++ sys.exit(0)++def check(ctx):+ Logs.warn('Nothing to do')++# this function is called before any other for parsing the command-line+def options(opt):++ # generate waf+ opt.add_option('--make-waf', action='store_true', default=False,+ help='creates the waf script', dest='waf')++ opt.add_option('--zip-type', action='store', default='bz2',+ help='specify the zip type [Allowed values: %s]' % ' '.join(zip_types), dest='zip')++ opt.add_option('--make-batch', action='store_true', default=False,+ help='creates a convenience waf.bat file (done automatically on win32 systems)',+ dest='make_batch')++ opt.add_option('--yes', action='store_true', default=False,+ help=optparse.SUPPRESS_HELP,+ dest='yes')++ # those ones are not too interesting+ opt.add_option('--set-version', default='',+ help='sets the version number for waf releases (for the maintainer)', dest='setver')++ opt.add_option('--strip', action='store_true', default=True,+ help='shrinks waf (strip docstrings, saves 33kb)',+ dest='strip_comments')+ opt.add_option('--nostrip', action='store_false', help='no shrinking',+ dest='strip_comments')+ opt.add_option('--tools', action='store', help='Comma-separated 3rd party tools to add, eg: "compat,ocaml" [Default: "compat15"]',+ dest='add3rdparty', default='compat15')+ opt.add_option('--prelude', action='store', help='Code to execute before calling waf', dest='prelude', default=PRELUDE)+ opt.load('python')++def compute_revision():+ global REVISION++ def visit(arg, dirname, names):+ for pos, name in enumerate(names):+ if name[0] == '.' or name in ['_build_', 'build']:+ del names[pos]+ elif name.endswith('.py'):+ arg.append(os.path.join(dirname, name))+ sources = []+ os.path.walk('waflib', visit, sources)+ sources.sort()+ m = md5()+ for source in sources:+ f = open(source,'rb')+ readBytes = 100000+ while (readBytes):+ readString = f.read(readBytes)+ m.update(readString)+ readBytes = len(readString)+ f.close()+ REVISION = m.hexdigest()++def process_tokens(tokens):+ accu = []+ prev = tokenize.NEWLINE++ indent = 0+ line_buf = []++ for (type, token, start, end, line) in tokens:+ token = token.replace('\r\n', '\n')+ if type == tokenize.NEWLINE:+ if line_buf:+ accu.append(indent * '\t')+ ln = "".join(line_buf)+ if ln == 'if __name__=="__main__":': break+ #ln = ln.replace('\n', '')+ accu.append(ln)+ accu.append('\n')+ line_buf = []+ prev = tokenize.NEWLINE+ elif type == tokenize.INDENT:+ indent += 1+ elif type == tokenize.DEDENT:+ indent -= 1+ elif type == tokenize.NAME:+ if prev == tokenize.NAME or prev == tokenize.NUMBER: line_buf.append(' ')+ line_buf.append(token)+ elif type == tokenize.NUMBER:+ if prev == tokenize.NAME or prev == tokenize.NUMBER: line_buf.append(' ')+ line_buf.append(token)+ elif type == tokenize.STRING:+ if not line_buf and token.startswith('"'): pass+ else: line_buf.append(token)+ elif type == tokenize.COMMENT:+ pass+ elif type == tokenize.OP:+ line_buf.append(token)+ else:+ if token != "\n": line_buf.append(token)++ if token != '\n':+ prev = type++ body = "".join(accu)+ return body++deco_re = re.compile('(def|class)\\s+(\w+)\\(.*')+def process_decorators(body):+ lst = body.split('\n')+ accu = []+ all_deco = []+ buf = [] # put the decorator lines+ for line in lst:+ if line.startswith('@'):+ buf.append(line[1:])+ elif buf:+ name = deco_re.sub('\\2', line)+ if not name:+ raise IOError("decorator not followed by a function!" + line)+ for x in buf:+ all_deco.append("%s(%s)" % (x, name))+ accu.append(line)+ buf = []+ else:+ accu.append(line)+ return "\n".join(accu+all_deco)++def sfilter(path):+ if sys.version_info[0] >= 3 and Options.options.strip_comments:+ f = open(path, "rb")+ try:+ tk = tokenize.tokenize(f.readline)+ next(tk) # the first one is always tokenize.ENCODING for Python 3, ignore it+ cnt = process_tokens(tk)+ finally:+ f.close()+ elif Options.options.strip_comments and path.endswith('.py'):+ f = open(path, "r")+ try:+ cnt = process_tokens(tokenize.generate_tokens(f.readline))+ finally:+ f.close()+ else:+ f = open(path, "r")+ try:+ cnt = f.read()+ finally:+ f.close()++ if path.endswith('.py') :+ # WARNING: since we now require python 2.4, we do not process the decorators anymore+ # if you need such a thing, uncomment the code below:+ #cnt = process_decorators(cnt)+ #if cnt.find('set(') > -1:+ # cnt = 'import sys\nif sys.hexversion < 0x020400f0: from sets import Set as set\n' + cnt+ cnt = '#! /usr/bin/env python\n# encoding: utf-8\n# WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file\n\n' + cnt++ if sys.hexversion > 0x030000f0:+ return (io.BytesIO(cnt.encode('utf-8')), len(cnt), cnt)+ return (io.BytesIO(cnt), len(cnt), cnt)++def create_waf(*k, **kw):+ mw = 'tmp-waf-'+VERSION+ print("-> preparing %r" % mw)++ import tarfile, re++ zipType = Options.options.zip.strip().lower()+ if zipType not in zip_types:+ zipType = zip_types[0]++ #open a file as tar.[extension] for writing+ tar = tarfile.open('%s.tar.%s' % (mw, zipType), "w:%s" % zipType)++ files = []+ add3rdparty = []+ for x in Options.options.add3rdparty.split(','):+ if os.path.isabs(x):+ files.append(x)+ else:+ add3rdparty.append(x + '.py')++ for d in '. Tools extras'.split():+ dd = os.path.join('waflib', d)+ for k in os.listdir(dd):+ if k == '__init__.py':+ files.append(os.path.join(dd, k))+ continue+ if d == 'extras':+ if not k in add3rdparty:+ continue+ if k.endswith('.py'):+ files.append(os.path.join(dd, k))++ for x in files:+ tarinfo = tar.gettarinfo(x, x)+ tarinfo.uid = tarinfo.gid = 0+ tarinfo.uname = tarinfo.gname = 'root'+ (code, size, cnt) = sfilter(x)+ tarinfo.size = size++ if os.path.isabs(x):+ tarinfo.name = 'waflib/extras/' + os.path.split(x)[1]++ tar.addfile(tarinfo, code)+ tar.close()++ f = open('waf-light', 'rU')+ try:+ code1 = f.read()+ finally:+ f.close()++ # now store the revision unique number in waf+ #compute_revision()+ #reg = re.compile('^REVISION=(.*)', re.M)+ #code1 = reg.sub(r'REVISION="%s"' % REVISION, code1)+ code1 = code1.replace("if sys.hexversion<0x206000f:\n\traise ImportError('Python >= 2.6 is required to create the waf file')\n", '')+ code1 = code1.replace('\t#import waflib.extras.compat15#PRELUDE', Options.options.prelude)++ prefix = ''+ reg = re.compile('^INSTALL=(.*)', re.M)+ code1 = reg.sub(r'INSTALL=%r' % prefix, code1)+ #change the tarfile extension in the waf script+ reg = re.compile('bz2', re.M)+ code1 = reg.sub(zipType, code1)+ if zipType == 'gz':+ code1 = code1.replace('bunzip2', 'gzip -d')++ f = open('%s.tar.%s' % (mw, zipType), 'rb')+ try:+ cnt = f.read()+ finally:+ f.close()++ # the REVISION value is the md5 sum of the binary blob (facilitate audits)+ m = md5()+ m.update(cnt)+ REVISION = m.hexdigest()+ reg = re.compile('^REVISION=(.*)', re.M)+ code1 = reg.sub(r'REVISION="%s"' % REVISION, code1)++ def find_unused(kd, ch):+ for i in range(35, 125):+ for j in range(35, 125):+ if i==j: continue+ if i == 39 or j == 39: continue+ if i == 92 or j == 92: continue+ s = chr(i) + chr(j)+ if -1 == kd.find(s.encode()):+ return (kd.replace(ch.encode(), s.encode()), s)+ raise++ # The reverse order prevent collisions+ (cnt, C2) = find_unused(cnt, '\r')+ (cnt, C1) = find_unused(cnt, '\n')+ ccc = code1.replace("C1='x'", "C1='%s'" % C1).replace("C2='x'", "C2='%s'" % C2)++ f = open('waf', 'wb')+ try:+ f.write(ccc.encode())+ f.write(to_bytes('#==>\n#'))+ f.write(cnt)+ f.write(to_bytes('\n#<==\n'))+ finally:+ f.close()++ if sys.platform == 'win32' or Options.options.make_batch:+ f = open('waf.bat', 'w')+ try:+ f.write('@python -x "%~dp0waf" %* & exit /b\n')+ finally:+ f.close()++ if sys.platform != 'win32':+ os.chmod('waf', Utils.O755)+ os.unlink('%s.tar.%s' % (mw, zipType))++def make_copy(inf, outf):+ (a, b, cnt) = sfilter(inf)+ f = open(outf, "wb")+ try:+ f.write(cnt)+ finally:+ f.close()++def configure(conf):+ conf.load('python')+ conf.check_python_version((2,4))++def build(bld):+ waf = bld.path.make_node('waf') # create the node right here+ bld(name='create_waf', rule=create_waf, target=waf, always=True, color='PINK', update_outputs=True)+