diff --git a/SConstruct b/SConstruct index 5179bba..2dcdbe1 100644 --- a/SConstruct +++ b/SConstruct @@ -21,11 +21,17 @@ SCons construction environment can be customized in sconscript.local script. """ import os +from os.path import join as pjoin import platform def subdictionary(d, keyset): return dict(kv for kv in d.items() if kv[0] in keyset) +def getsyspaths(*names): + pall = sum((os.environ.get(n, '').split(os.pathsep) for n in names), []) + rv = [p for p in pall if os.path.exists(p)] + return rv + # copy system environment variables related to compilation DefaultEnvironment(ENV=subdictionary(os.environ, ''' PATH CPATH CPLUS_INCLUDE_PATH LIBRARY_PATH LD_RUN_PATH @@ -43,26 +49,71 @@ env.EnsureSConsVersion(0, 98, 1) # Customizable compile variables vars = Variables('sconsvars.py') -vars.Add(PathVariable( - 'prefix', - 'installation prefix directory', - '/usr/local')) -vars.Update(env) -vars.Add(PathVariable( - 'libdir', - 'installation directory for compiled library [prefix/lib]', - env['prefix'] + '/lib', - PathVariable.PathAccept)) -vars.Add(PathVariable( - 'includedir', - 'installation directory for C++ header files [prefix/include]', - env['prefix'] + '/include', - PathVariable.PathAccept)) -vars.Add(PathVariable( - 'datadir', - 'installation directory for architecture independent data [prefix/share]', - env['prefix'] + '/share', - PathVariable.PathAccept)) +if 'PREFIX' in os.environ: + vars.Add(PathVariable( + 'prefix', + 'installation prefix directory', + os.environ['prefix'])) + vars.Update(env) +elif 'CONDA_PREFIX' in os.environ: + vars.Add(PathVariable( + 'prefix', + 'installation prefix directory', + os.environ['CONDA_PREFIX'])) + vars.Update(env) +else: + vars.Add(PathVariable( + 'prefix', + 'installation prefix directory', + '/usr/local')) + vars.Update(env) + +if platform.system().lower() == 'windows': + vars.Add(PathVariable( + 'libdir', + 'installation directory for compiled programs [prefix/Library/lib]', + pjoin(env['prefix'], 'Library', 'Lib'), + PathVariable.PathAccept)) + vars.Add(PathVariable( + 'includedir', + 'installation directory for C++ header files [prefix/Library/include]', + pjoin(env['prefix'], 'Library', 'include'), + PathVariable.PathAccept)) + vars.Add(PathVariable( + 'datadir', + 'installation directory for architecture independent data [prefix/share]', + pjoin(env['prefix'], 'Library', 'share'), + PathVariable.PathAccept)) + + env['ENV']['TMP'] = os.environ['TMP'] + env.Append(CPPPATH=[pjoin(env['prefix'], 'Library', 'include')]) + env.Append(LIBPATH=pjoin(env['prefix'], 'Library', 'lib')) + + env.Append(CPPDEFINES=['_USE_MATH_DEFINES']) + +else: + # Installation paths + vars.Add(PathVariable( + 'libdir', + 'installation directory for compiled library [prefix/lib]', + pjoin(env['prefix'], 'lib'), + PathVariable.PathAccept)) + vars.Add(PathVariable( + 'includedir', + 'installation directory for C++ header files [prefix/include]', + pjoin(env['prefix'], 'include'), + PathVariable.PathAccept)) + vars.Add(PathVariable( + 'datadir', + 'installation directory for architecture independent data [prefix/share]', + pjoin(env['prefix'], 'share'), + PathVariable.PathAccept)) + + env.Append(CPPPATH=[pjoin(env['prefix'], 'include')]) + env.Append(LIBPATH=[pjoin(env['prefix'], 'lib')]) + + + vars.Add(EnumVariable( 'build', 'compiler settings', @@ -83,9 +134,13 @@ vars.Add( vars.Add(BoolVariable( 'test_installed', 'build tests using the installed library.', False)) + vars.Update(env) env.Help(MY_SCONS_HELP % vars.GenerateHelpText(env)) +env.PrependUnique(LIBPATH=getsyspaths('LIBRARY_PATH')) +env.AppendUnique(CPPDEFINES='BOOST_ALL_NO_LIB') + env['has_objcryst'] = None btags = [env['build'], platform.machine()] if env['profile']: btags.append('profile') diff --git a/src/SConscript b/src/SConscript index fce570e..3bc82da 100644 --- a/src/SConscript +++ b/src/SConscript @@ -1,4 +1,5 @@ import os +import platform Import('env') @@ -21,8 +22,6 @@ fast_linkflags = ['-s'] # Specify minimum C++ standard. Allow later standard from sconscript.local. # In case of multiple `-std` options the last option holds. -env.PrependUnique(CXXFLAGS='-std=c++11', delete_existing=1) - # Platform specific intricacies. if env['PLATFORM'] == 'darwin': env.AppendUnique(CXXFLAGS='-ftemplate-depth-256') @@ -31,31 +30,39 @@ if env['PLATFORM'] == 'darwin': fast_linkflags[:] = [] # Compiler specific options -if icpc: - # options for Intel C++ compiler on hpc dev-intel07 - env.PrependUnique(CCFLAGS=['-w1', '-fp-model', 'precise']) - env.PrependUnique(LIBS=['imf']) - fast_optimflags = ['-fast', '-no-ipo'] -else: - # g++ options - env.PrependUnique(CCFLAGS=['-Wall']) - fast_optimflags = ['-ffast-math'] - -# Configure build variants -if env['build'] == 'debug': - env.Append(CCFLAGS='-g') -elif env['build'] == 'coverage': - env.CacheDir(None) - env.Append(CCFLAGS=['-g', '--coverage', '-O0']) - env.Append(LINKFLAGS='--coverage') -elif env['build'] == 'fast': - env.AppendUnique(CCFLAGS=['-O3'] + fast_optimflags) - env.AppendUnique(CPPDEFINES={'NDEBUG' : None}) - env.AppendUnique(LINKFLAGS=fast_linkflags) - -if env['profile']: - env.AppendUnique(CCFLAGS='-pg') - env.AppendUnique(LINKFLAGS='-pg') +if platform.system().lower() == "windows": + # Visual c++ + env.PrependUnique(CCFLAGS=['/Ox', '/EHsc', '/MD', '/std:c++14', '/Wall']) + env.AppendUnique(CPPDEFINES={'NDEBUG': None}) + env.AppendUnique(LINKFLAGS=['/OPT:NOREF', '/OPT:NOICF', '/WHOLEARCHIVE:diffpy.lib']) + # env.AppendUnique(LINKFLAGS='/EXPORT') +else: + env.PrependUnique(CXXFLAGS='-std=c++11') + if icpc: + # options for Intel C++ compiler on hpc dev-intel07 + env.PrependUnique(CCFLAGS=['-w1', '-fp-model', 'precise']) + env.PrependUnique(LIBS=['imf']) + fast_optimflags = ['-fast', '-no-ipo'] + else: + # g++ options + env.PrependUnique(CCFLAGS=['-Wall']) + fast_optimflags = ['-ffast-math'] + + # Configure build variants + if env['build'] == 'debug': + env.Append(CCFLAGS='-g') + elif env['build'] == 'coverage': + env.CacheDir(None) + env.Append(CCFLAGS=['-g', '--coverage', '-O0']) + env.Append(LINKFLAGS='--coverage') + elif env['build'] == 'fast': + env.AppendUnique(CCFLAGS=['-O3'] + fast_optimflags) + env.AppendUnique(CPPDEFINES={'NDEBUG' : None}) + env.AppendUnique(LINKFLAGS=fast_linkflags) + + if env['profile']: + env.AppendUnique(CCFLAGS='-pg') + env.AppendUnique(LINKFLAGS='-pg') # configure boost and ObjCryst libraries unless non-relevant. @@ -117,11 +124,15 @@ if 'sdist' in COMMAND_LINE_TARGETS: # use new environment with extra libraries needed for libdiffpy. env_lib = env.Clone() # Setup GSL, the GNU Scientific library. -env_lib.ParseConfig("gsl-config --cflags --libs") # The dladdr call in runtimepath.cpp requires the dl library. -env_lib.AppendUnique(LIBS=['dl']) +env_lib.AppendUnique(LIBS=['dl', 'gsl', 'gslcblas']) + +if platform.system().lower() == "windows": + # Use a static library (does not require __declspec(dllexport) all over the code) + libdiffpy = env_lib.StaticLibrary('diffpy', env['lib_sources']) +else: + libdiffpy = env_lib.SharedLibrary('diffpy', env['lib_sources']) -libdiffpy = env_lib.SharedLibrary('diffpy', env['lib_sources']) # Clean up .gcda and .gcno files from coverage analysis. env_lib.Clean(libdiffpy, Glob('diffpy/*.gc??')) env_lib.Clean(libdiffpy, Glob('diffpy/srreal/*.gc??')) diff --git a/src/SConscript.configure b/src/SConscript.configure index 0892b10..d796bb5 100644 --- a/src/SConscript.configure +++ b/src/SConscript.configure @@ -19,6 +19,16 @@ def CheckBoostVersion(context, version): context.Result(rv) return rv +def CheckBoostSerialization(context): + context.Message('Checking for boost_serialization... ') + test_code = ''' + #include <boost/serialization/serialization.hpp> + int main() { return 0; } + ''' + rv = context.TryCompile(test_code, '.cpp') + context.Result(rv) + return rv + # Helper functions ----------------------------------------------------------- boostlibtags = ['', '-mt'] @@ -40,10 +50,12 @@ def configure_boost_library(libname): print('This program requires %r library' % libname) Exit(1) + # Start configuration -------------------------------------------------------- conf = Configure(env, custom_tests={ 'CheckBoostVersion' : CheckBoostVersion, + 'CheckBoostSerialization': CheckBoostSerialization }) # serialization of unordered_map requires boost 1.56.0 @@ -52,8 +64,9 @@ if not conf.CheckBoostVersion(boost_required): print('This software requires Boost %s or later.' % boost_required) Exit(1) -# boost_serialization -configure_boost_library('boost_serialization') +if not conf.CheckBoostSerialization(): + print('Boost.Serialization library not found!') + Exit(1) # ObjCryst - assume a no-objcryst fallback configuration. conf.env['has_objcryst'] = False diff --git a/src/diffpy/SConscript b/src/diffpy/SConscript index 8e3c07d..c08a605 100644 --- a/src/diffpy/SConscript +++ b/src/diffpy/SConscript @@ -1,4 +1,5 @@ import os +import platform Import('env', 'GlobSources') @@ -7,6 +8,9 @@ env['lib_sources'] += [f for f in GlobSources('*.cpp') if str(f) != 'runtimepath.cpp'] rtrp = os.path.relpath(env['runtimepath'], env['libdir']) +if platform.system().lower() == 'windows': + rtrp = rtrp.replace('\\', '/') + env_rt = env.Clone() env_rt.AppendUnique(CPPDEFINES=dict(DIFFPYRUNTIMERELPATH=rtrp)) rtso = env_rt.SharedObject('runtimepath', 'runtimepath.cpp') diff --git a/src/diffpy/boost_throw_exception.cpp b/src/diffpy/boost_throw_exception.cpp new file mode 100644 index 0000000..96f9fcf --- /dev/null +++ b/src/diffpy/boost_throw_exception.cpp @@ -0,0 +1,10 @@ +#include <stdexcept> +#include <boost/throw_exception.hpp> + +namespace boost { + void throw_exception(std::exception const & e) + { + // You can also customize the behavior here if needed. + throw e; + } +} diff --git a/src/diffpy/mathutils.ipp b/src/diffpy/mathutils.ipp index acf4d24..2c60d83 100644 --- a/src/diffpy/mathutils.ipp +++ b/src/diffpy/mathutils.ipp @@ -34,12 +34,6 @@ inline double remainder(double x, double y) fmod(x, y) : (fmod(x, y) + y); } - -inline double log2(double x) -{ - return log(x) / log(2.0); -} - #endif // _MSC_VER namespace diffpy { diff --git a/src/diffpy/runtimepath.cpp b/src/diffpy/runtimepath.cpp index 0957e74..0f7299e 100644 --- a/src/diffpy/runtimepath.cpp +++ b/src/diffpy/runtimepath.cpp @@ -23,8 +23,57 @@ #include <sstream> #include <stdexcept> #include <sys/stat.h> -#include <dlfcn.h> +#include <dlfcn.h> // not available on Windows, conda install dlfcn-win32 + +// libgen.h is not available on Windows +#ifdef _WIN32 +#include <string> +#include <algorithm> + +// A simple replacement for dirname() on Windows. +inline std::string win_dirname(const std::string& path) +{ + // Find the last occurrence of either '\' or '/' + size_t pos = path.find_last_of("\\/"); + if (pos == std::string::npos) + return "."; // No directory found, return current directory + return path.substr(0, pos); +} + +// Overload to match the expected C-style interface if needed: +inline char* dirname(char* path) +{ + static std::string dir; + dir = win_dirname(std::string(path)); + return const_cast<char*>(dir.c_str()); +} +#else #include <libgen.h> +#endif + +// S_ISDIR, PATH_MAX, realpath, etc. +#ifdef _WIN32 +#include <windows.h> +#include <stdlib.h> // for _fullpath +#include <sys/stat.h> // for _stat +#include <direct.h> // for _getcwd, etc. + +// Define S_ISDIR using the Windows _S_IFDIR flag from sys/stat.h. +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode) & _S_IFDIR) == _S_IFDIR) +#endif + +// Use MAX_PATH from <windows.h> as PATH_MAX if not defined. +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH +#endif + +// Define realpath in terms of _fullpath. +// _fullpath returns a pointer to the resolved path in the buffer you provide. +// The usage should be nearly equivalent. +#define realpath(N, R) _fullpath((R), (N), PATH_MAX) +#endif + #include <diffpy/version.hpp> #include <diffpy/runtimepath.hpp> diff --git a/src/diffpy/srreal/StructureAdapter.hpp b/src/diffpy/srreal/StructureAdapter.hpp index 1ff4218..7ebe5e7 100644 --- a/src/diffpy/srreal/StructureAdapter.hpp +++ b/src/diffpy/srreal/StructureAdapter.hpp @@ -32,6 +32,12 @@ #include <diffpy/srreal/R3linalg.hpp> #include <diffpy/srreal/BaseBondGenerator.hpp> +#ifdef _MSC_VER + #define DEPRECATED __declspec(deprecated) +#else + #define DEPRECATED __attribute__((deprecated)) +#endif + namespace diffpy { namespace srreal { @@ -89,9 +95,7 @@ class StructureAdapter : /// this method allows custom special configuration for a concrete /// pair of StructureAdapter and PairQuantity objects. - virtual void customPQConfig(PairQuantity* pq) const - __attribute__ ((deprecated)) - { } + virtual DEPRECATED void customPQConfig(PairQuantity* pq) const { } /// Return difference from the other StructureAdapter virtual StructureDifference diff(StructureAdapterConstPtr) const;