import libtbx.load_env from libtbx.str_utils import show_string from libtbx.utils import \ warn_if_unexpected_md5_hexdigest, \ write_this_is_auto_generated from libtbx.env_config import darwin_shlinkcom import string import sys, os op = os.path Import("env_base", "env_etc") env_etc.boost_dist = libtbx.env.dist_path("boost") env_etc.boost_include = env_etc.boost_dist env_etc.boost_adaptbx_dist = libtbx.env.dist_path("boost_adaptbx") env_etc.boost_adaptbx_include = os.path.dirname(env_etc.boost_adaptbx_dist) def determine_boost_version(): test_code = """\ #include #include int main() { std::cout << BOOST_VERSION << std::endl; return 0; } """ env = env_base.Clone( CPPPATH=[env_etc.boost_include], CFLAGS=env_etc.cflags_base, CCFLAGS=env_etc.ccflags_base, CXXFLAGS=env_etc.cxxflags_base) conf = env.Configure() flag, output = conf.TryRun(test_code, extension='.cpp') conf.Finish() if (not flag): return -1 return int(output) env_etc.boost_version = determine_boost_version() print "BOOST_VERSION: %i" %env_etc.boost_version if (not env_etc.no_boost_python): env_etc.cxxflags_bpl_defines_base = [ "-DBOOST_PYTHON_MAX_BASES=2"] if (libtbx.env.build_options.boost_python_no_py_signatures): env_etc.cxxflags_bpl_defines_base.append( "-DBOOST_PYTHON_NO_PY_SIGNATURES") env_no_includes_boost_python_ext = env_base.Clone( SHLINKFLAGS=env_etc.shlinkflags_bpl, SHLIBPREFIX="", LIBS=["boost_python"] + env_etc.libs_python + env_etc.libm) env_no_includes_boost_python_ext.Append( LIBPATH=env_etc.libpath_python) env_no_includes_boost_python_ext.Append( SHCXXFLAGS=env_etc.cxxflags_bpl_defines_base, PCHPDBFLAGS=env_etc.cxxflags_bpl_defines_base) env_no_includes_boost_python_ext.Replace( SHLIBSUFFIX=env_etc.extension_module_suffix) if (env_etc.compiler == "win32_cl" and env_etc.have_manifest_tool): env_no_includes_boost_python_ext.Append( SHLINKCOM=[ 'mt /nologo /outputresource:"${TARGET};#2"' ' /manifest ${TARGET}.manifest']) elif (env_etc.mac_os_use_dsymutil): # Debugging Boost.Python module C++ code works much more reliably # with the DWARF + dSYM format. Hence run dsymutil after building *.so env = env_no_includes_boost_python_ext env['SHLINKCOM'] = [env['SHLINKCOM'], 'dsymutil $TARGET'] Export("env_no_includes_boost_python_ext") env_pure_boost_python_ext = env_no_includes_boost_python_ext.Clone() env_etc.include_registry.set_boost_dir_name(env_etc.boost_dist) env_etc.include_registry.append( env=env_pure_boost_python_ext, paths=[ libtbx.env.under_build("include"), env_etc.boost_include, env_etc.python_include]) conf = env_pure_boost_python_ext.Clone().Configure() if (not conf.TryCompile("#include ", extension=".cpp")): raise RuntimeError("""\ FATAL: ********************** C++ compiler does not work. ********************** See config.log for details. """) conf.Finish() conf = env_pure_boost_python_ext.Clone().Configure() if (not conf.TryCompile("#include ", extension=".cpp")): raise RuntimeError("""\ FATAL: ******************** Python.h include not available. ******************** On some Linux machines you may need to install the "python-dev" package, e.g. with "yum install python-dev" or "apt-get install python-dev". """) conf.Finish() env_boost_python_ext = env_pure_boost_python_ext.Clone() env_etc.include_registry.prepend( env=env_boost_python_ext, paths=[env_etc.libtbx_include]) Export("env_boost_python_ext") # Precompiled headers for the like of Boost Python, standard library, etc. if libtbx.env.build_options.precompile_headers: if sys.platform == 'win32': precompiled_cpp = '#' + os.path.join('boost_adaptbx', 'precompiled.cpp') precompiled_h = 'boost_adaptbx/precompiled.h' env_no_includes_boost_python_ext['PCH'], _ \ = env_boost_python_ext.PCH(precompiled_cpp) env_no_includes_boost_python_ext['PCHSTOP'] = precompiled_h env_no_includes_boost_python_ext.Append(CPPFLAGS=[ '/FI' + precompiled_h ]) elif env_etc.compiler.endswith('clang'): # 1st trick: # use Command to execute $SHCXXCOM with an extra option to produce # a precompiled header a la clang precompiled_h_gch = "#boost_adaptbx/precompiled.h.gch" env_pch = env_pure_boost_python_ext.Clone() env_pch.Append(SHCXXFLAGS=[ '-x', 'c++-header' ]) env_pch.Command(target=precompiled_h_gch, source="precompiled.h", action="$SHCXXCOM") # 2nd trick # use an emitter so that the dependency on the precompiled header # is added on-the-fly to the target of SharedLibrary # (got the idea from http://scons.org/wiki/GchBuilder) explicit_include = [ '-include', 'boost_adaptbx/precompiled.h' ] def gcc_style_pch_emitter(target, source, env): import SCons.Defaults # emitters are not chained, so we need to call the default one # otherwise some setup is not done and scons will refuse to link # shared libraries from what it thinks are static objects SCons.Defaults.SharedObjectEmitter(target, source, env) env.Depends(target, precompiled_h_gch) return target, source for env in (env_pure_boost_python_ext, env_no_includes_boost_python_ext): env.Append(SHCXXFLAGS=explicit_include) for suffix in ('.cxx', '.cpp', '.cc'): env['BUILDERS']['SharedObject'].add_emitter(suffix, gcc_style_pch_emitter) env_pure_boost_python_ext.SharedLibrary( target="#lib/boost_python_hybrid_times_ext", source="hybrid_times_ext.cpp") env_pure_boost_python_ext.SharedLibrary( target="#lib/boost_rational_ext", source="rational_ext.cpp") env = env_pure_boost_python_ext.Clone() env_etc.include_registry.prepend( env=env, paths=[env_etc.boost_adaptbx_include]) env.SharedLibrary( target="#lib/boost_python_meta_ext", source="meta_ext.cpp") env.SharedLibrary( target="#lib/boost_optional_ext", source="optional_ext.cpp") env.SharedLibrary( target="#lib/std_pair_ext", source="std_pair_ext.cpp") env.SharedLibrary( target="#lib/boost_tuple_ext", source="tuple_ext.cpp") env.SharedLibrary( target="#lib/boost_adaptbx_python_streambuf_test_ext", source="tests/python_streambuf_test_ext.cpp") env = env_base.Clone() env_etc.include_registry.prepend( env=env, paths=[env_etc.boost_adaptbx_include]) env.Program( target="tests/tst_optional_copy", source="tests/tst_optional_copy.cpp") import os, os.path env = env_base.Clone(LIBS=env_etc.libs_python) env.Append(LIBPATH=env_etc.libpath_python) env.Append(SHCXXFLAGS=env_etc.cxxflags_bpl_defines_base) env.Append(SHCXXFLAGS=["-DBOOST_PYTHON_SOURCE"]) if (libtbx.env.build_options.boost_python_bool_int_strict): env.Append(SHCXXFLAGS=["-DBOOST_PYTHON_BOOL_INT_STRICT"]) env.Replace(SHLINKFLAGS=env_etc.shlinkflags) env.Append(CXXFLAGS=env_etc.cxxflags_bpl_defines_base) env.Append(CXXFLAGS="-DBOOST_PYTHON_SOURCE") env.Replace(LINKFLAGS=env_etc.shlinkflags) env_etc.include_registry.append( env=env, paths=[env_etc.boost_include, env_etc.python_include]) darwin_shlinkcom(env_etc, env, lo="boost/libs/python/src/libboost_python.lo", dylib="lib/libboost_python.dylib") # fixed list of file names introduced 2009-09-29, due to major changes in # boost/libs/python/build/Jamfile.v2 svn rev. 56305 (new Python 3 support) bpl_dll_sources = """\ numeric.cpp list.cpp long.cpp dict.cpp tuple.cpp str.cpp slice.cpp converter/from_python.cpp converter/registry.cpp converter/type_id.cpp object/enum.cpp object/class.cpp object/function.cpp object/inheritance.cpp object/life_support.cpp object/pickle_support.cpp errors.cpp module.cpp converter/builtin_converters.cpp converter/arg_to_python_base.cpp object/iterator.cpp object/stl_iterator.cpp object_protocol.cpp object_operators.cpp wrapper.cpp import.cpp exec.cpp object/function_doc_signature.cpp """.splitlines() prefix = "#"+os.path.join( os.path.basename(env_etc.boost_dist), "libs", "python", "src") bpl_dll_sources = [os.path.join(prefix, path) for path in bpl_dll_sources] # env.Repository(os.path.dirname(env_etc.boost_dist)) if (env_etc.static_bpl): env.StaticLibrary(target="#lib/boost_python", source=bpl_dll_sources) else: env.SharedLibrary(target="#lib/boost_python", source=bpl_dll_sources) if (bool(int(ARGUMENTS.get("boost_python_tests", "0")))): warn_if_unexpected_md5_hexdigest( path=libtbx.env.under_dist("boost", "libs/python/test/Jamfile.v2"), expected_md5_hexdigests=[ "c7a3dd81bf730635146f5c908ac982eb", # svn revision 39065M "d40aac0029bcd28f6e205ae3b30a1284", # svn revision 40216 "b79f016d3ec10cf1625a9e006e605428", # svn revision 40714 "f948983d970fd47e83a3a785bb54520a", # svn revision 41550 "c3d84006331d534840c42ab956fdfa05", # svn revision 50367M "cedfd061d767a27413ef4a75ee0e446f", # svn revision 56310 "e5507482a1937825e4c9f3ffe555fc59", # svn revision 59331 "351b57c6a60e484925ca0cb9ed0f8ade", # svn revision 61086 "4fb583110f7424c341a0dd44ff3b3a2d", # svn revision 69551 "fdde4c7231c301c3150b0a5605045914", # svn revision 72175 ]) bpl_tests = Split(""" staticmethod shared_ptr enable_shared_from_this andreas_beyer polymorphism polymorphism2 auto_ptr minimal args numpy enum exception_translator test_pointer_adoption operators callbacks defaults object list long dict tuple str virtual_functions back_reference implicit data_members ben_scott1 bienstman1 bienstman2 bienstman3 multi_arg_constructor extract opaque pickle1 pickle2 pickle3 pickle4 nested docstring pytype_function bienstman4 bienstman5 test_builtin_converters,builtin_converters_ext,test_builtin_converters cltree,cltree,test_cltree m1,m1,newtest m2,m2,newtest iterator,iterator_ext,iterator input_iterator,input_iterator,iterator crossmod_exception_a,crossmod_exception_a,crossmod_exception crossmod_exception_b,crossmod_exception_b,crossmod_exception vector_indexing_suite return_arg keywords,keywords,keywords_test properties map_indexing_suite;int_map_indexing_suite;a_map_indexing_suite,map_indexing_suite_ext,map_indexing_suite injected slice const_argument raw_ctor pointer_vector wrapper_held_type polymorphism2_auto_ptr stl_iterator voidptr crossmod_opaque_a,crossmod_opaque_a,crossmod_opaque crossmod_opaque_b,crossmod_opaque_b,crossmod_opaque class """) # non-portable tests are not included above: # calling_conventions # calling_conventions_mf # Import("env_boost_python_ext") test_dir = libtbx.env.under_dist("boost", "libs/python/test") prefix = "#"+os.path.join( os.path.basename(env_etc.boost_dist), "libs", "python", "test") all_tst = [] for bpl_test in bpl_tests: flds = bpl_test.split(",") assert len(flds) in (1,3) if (len(flds) == 1): src = bpl_test pyd = bpl_test + "_ext" tst = bpl_test else: src = flds[0] pyd = flds[1] tst = flds[2] env = env_pure_boost_python_ext.Clone() env.Repository(os.path.dirname(env_etc.boost_dist)) ok = True source = [] for s in src.split(";"): cpp = "%s.cpp" % s file_name = os.path.join(test_dir, cpp) if (not os.path.isfile(file_name)): print "Warning: source file not available:", show_string(file_name) ok = False else: source.append(os.path.join(prefix, cpp)) if (ok): if (not tst in all_tst): all_tst.append(tst) env.SharedLibrary(target="#lib/%s" % pyd, source=source) all_tst = [os.path.join(test_dir, tst+".py") for tst in all_tst] # if (sys.platform == "linux2"): base_lib = libtbx.env.under_build(path="base/lib") if (os.path.isdir(base_lib)): env_prog = env.Clone() env_prog.Append(LIBPATH=[base_lib]) env_prog.Append(LIBS=[ "-lpython%d.%d" % sys.version_info[:2], "-lpthread", "-lutil", "-ldl"]) exe = env_prog.Program( target="boost/libs/python/test/exec_dynamic", source=[os.path.join(prefix, "exec.cpp")]) libtbx.env.write_dispatcher_in_bin( source_file=exe[0].get_abspath(), target_file="boost_libs_python_test_exec_dynamic") all_tst.append("$ boost_libs_python_test_exec_dynamic %s" % show_string(os.path.join(test_dir, "exec.py"))) # if (os.name != "nt"): env.SharedLibrary( target="#lib/boost_adaptbx_char_array_ext", source=["char_array_ext.cpp"]) all_tst.append( libtbx.env.under_dist("boost_adaptbx", "tests/tst_char_array.py")) # if (os.name == "nt"): boost_python_run_tests = \ "%s\\boost_python_run_tests.bat" % libtbx.env.build_path f = open(boost_python_run_tests, "w") for tst in all_tst: if (tst.startswith("$ ")): print >> f, 'call %s' % tst[2:] else: print >> f, 'call libtbx.python %s' % show_string(tst) f.close() else: boost_python_run_tests = \ "%s/boost_python_run_tests.csh" % abs(libtbx.env.build_path) f = open(boost_python_run_tests, "w") print >> f, "#! /bin/csh -f" print >> f, "set verbose" for tst in all_tst: if (tst.startswith("$ ")): print >> f, tst[2:] else: print >> f, 'libtbx.python "%s"' % show_string(tst) f.close() os.chmod(boost_python_run_tests, 0755) def write_type_id_eq_h(): unsigned_types = [ "unsigned short", "unsigned", "unsigned long", "unsigned long long"] test_code = """\ #include #include #include int main() { std::cout %s << std::endl; return 0; } """ % "\n".join([" << static_cast(typeid(%s) == typeid(size_t))" % u for u in unsigned_types]) env = env_base.Clone() conf = env.Configure() flag, output = conf.TryRun(test_code, extension='.cpp') conf.Finish() if (not flag): see_message_above = \ 'Failure building small C++ program for obtaining unsigned sizes.' \ ' Please inspect "config.log" for details' raise RuntimeError(see_message_above) output = output.rstrip() if ( len(output) != len(unsigned_types) or len(output.replace("0", "").replace("1", "")) != 0 or output.count("1") != 1): raise RuntimeError('Unexpected output: "%s"' % output) dir_name = libtbx.env.under_build("include/boost_adaptbx") if (not op.isdir(dir_name)): os.makedirs(dir_name) assert op.isdir(dir_name) if (1): # XXX backward compatibility 2009-10-14 file_name = op.join(dir_name, "boost_python_type_id_eq.h") if (op.isfile(file_name)): try: os.remove(file_name) except OSError: pass file_name = op.join(dir_name, "type_id_eq.h") f = open(file_name, "w") write_this_is_auto_generated( f=f, file_name_generator="cctbx_project/boost_adaptbx/SConscript") guard = "BOOST_ADAPTBX_TYPE_ID_EQ_H" print >> f, "#ifndef", guard print >> f, "#define", guard print >> f for u,c in zip(unsigned_types, output): if (c == "1"): print >> f, "#define BOOST_ADAPTBX_TYPE_ID_SIZE_T_EQ_" \ + u.replace(" ", "_").upper() print >> f print >> f, "#endif // GUARD" del f write_type_id_eq_h() if (os.path.isfile(libtbx.env.under_build("lib/libswig_class_example.a"))): # this example requires these manual steps: # gunzip -c swig-1.3.24.tar.gz | tar xf - # cd SWIG-1.3.24 # ./configure # make # cd Examples/python/class # make # cp _example.so example.py $LIBTBX_BUILD/lib # ar r $LIBTBX_BUILD/lib/libswig_class_example.a example.o env = env_pure_boost_python_ext.Clone() env.Prepend(LIBS=["swig_class_example"]) env.SharedLibrary( target="#lib/boost_python_swig_args_ext", source="swig_args_ext.cpp") if (os.path.isfile(libtbx.env.under_dist("boost_adaptbx", "demo.cpp"))): env = env_pure_boost_python_ext.Clone() env.SharedLibrary( target="#lib/demo", source="demo.cpp")