Skip to content

Commit 5f009ed

Browse files
authored
Merge pull request #34 from diffpy/windows
Update build for macOS, add windows
2 parents 7c43fa2 + be66030 commit 5f009ed

14 files changed

+397
-137
lines changed

SConstruct

Lines changed: 143 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,36 @@ SCons construction environment can be customized in sconscript.local script.
2020
"""
2121

2222
import os
23+
from os.path import join as pjoin
2324
import re
2425
import subprocess
2526
import platform
2627

28+
2729
def subdictionary(d, keyset):
2830
return dict(kv for kv in d.items() if kv[0] in keyset)
2931

32+
3033
def getsyspaths(*names):
3134
pall = sum((os.environ.get(n, '').split(os.pathsep) for n in names), [])
3235
rv = [p for p in pall if os.path.exists(p)]
3336
return rv
3437

38+
3539
def pyoutput(cmd):
3640
proc = subprocess.Popen([env['python'], '-c', cmd],
3741
stdout=subprocess.PIPE,
3842
universal_newlines=True)
3943
out = proc.communicate()[0]
4044
return out.rstrip()
4145

46+
4247
def pyconfigvar(name):
4348
cmd = ('from distutils.sysconfig import get_config_var\n'
4449
'print(get_config_var(%r))\n') % name
4550
return pyoutput(cmd)
4651

52+
4753
# copy system environment variables related to compilation
4854
DefaultEnvironment(ENV=subdictionary(os.environ, '''
4955
PATH PYTHONPATH GIT_DIR
@@ -53,7 +59,7 @@ DefaultEnvironment(ENV=subdictionary(os.environ, '''
5359
_PYTHON_SYSCONFIGDATA_NAME
5460
_CONDA_PYTHON_SYSCONFIGDATA_NAME
5561
'''.split())
56-
)
62+
)
5763

5864
# Create construction environment
5965
env = DefaultEnvironment().Clone()
@@ -64,18 +70,35 @@ env.EnsureSConsVersion(0, 98)
6470
# Customizable compile variables
6571
vars = Variables('sconsvars.py')
6672

67-
vars.Add(PathVariable('prefix',
68-
'installation prefix directory', None))
73+
# Set PREFIX for installation and linking
74+
# TODO: also amend paths when VIRTUAL_ENV variable exists ?
75+
if 'PREFIX' in os.environ:
76+
# building with a set prefix
77+
vars.Add(PathVariable(
78+
'prefix',
79+
'installation prefix directory',
80+
os.environ['PREFIX']))
81+
elif 'CONDA_PREFIX' in os.environ:
82+
# building for a conda environment
83+
vars.Add(PathVariable(
84+
'prefix',
85+
'installation prefix directory',
86+
os.environ['CONDA_PREFIX']))
87+
else:
88+
vars.Add(PathVariable('prefix',
89+
'installation prefix directory', None))
90+
vars.Update(env)
91+
6992
vars.Add(EnumVariable('build',
70-
'compiler settings', 'fast',
71-
allowed_values=('debug', 'fast')))
93+
'compiler settings', 'fast',
94+
allowed_values=('debug', 'fast')))
7295
vars.Add(EnumVariable('tool',
73-
'C++ compiler toolkit to be used', 'default',
74-
allowed_values=('default', 'intelc')))
96+
'C++ compiler toolkit to be used', 'default',
97+
allowed_values=('default', 'intelc', 'clang', 'clangxx')))
7598
vars.Add(BoolVariable('profile',
76-
'build with profiling information', False))
99+
'build with profiling information', False))
77100
vars.Add('python',
78-
'Python executable to use for installation.', 'python')
101+
'Python executable to use for installation.', 'python')
79102
vars.Update(env)
80103
env.Help(MY_SCONS_HELP % vars.GenerateHelpText(env))
81104

@@ -89,78 +112,120 @@ if env['tool'] == 'intelc':
89112
env.Tool('intelc', topdir=icpc[:icpc.rfind('/bin')])
90113

91114
# Figure out compilation switches, filter away C-related items.
92-
good_python_flag = lambda n : (
93-
not isinstance(n, str) or
94-
not re.match(r'(-g|-Wstrict-prototypes|-O\d|-fPIC)$', n))
115+
good_python_flag = lambda n: (
116+
not isinstance(n, str) or
117+
not re.match(r'(-g|-Wstrict-prototypes|-O\d|-fPIC)$', n))
95118

96119
# Determine python-config script name.
97-
pyversion = pyoutput('import sys; print("%i.%i" % sys.version_info[:2])')
98-
pycfgname = 'python%s-config' % (pyversion if pyversion[0] == '3' else '')
99-
# realpath gets the real path if exec is a link (e.g. in a python environment)
100-
xpython = os.path.realpath(env.WhereIs(env['python']))
101-
pybindir = os.path.dirname(xpython)
102-
pythonconfig = os.path.join(pybindir, pycfgname)
103-
104-
# Verify python-config comes from the same path as the target python.
105-
xpythonconfig = env.WhereIs(pythonconfig)
106-
if os.path.dirname(xpython) != os.path.dirname(xpythonconfig):
107-
print("Inconsistent paths of %r and %r" % (xpython, xpythonconfig))
108-
Exit(1)
109-
# Process the python-config flags here.
110-
env.ParseConfig(pythonconfig + " --cflags")
111-
env.Replace(CCFLAGS=[f for f in env['CCFLAGS'] if good_python_flag(f)])
112-
env.Replace(CPPDEFINES='BOOST_ERROR_CODE_HEADER_ONLY')
113-
# the CPPPATH directories are checked by scons dependency scanner
114-
cpppath = getsyspaths('CPLUS_INCLUDE_PATH', 'CPATH')
115-
env.AppendUnique(CPPPATH=cpppath)
116-
# Insert LIBRARY_PATH explicitly because some compilers
117-
# ignore it in the system environment.
118-
env.PrependUnique(LIBPATH=getsyspaths('LIBRARY_PATH'))
119-
# Add shared libraries.
120-
# Note: ObjCryst and boost_python are added from SConscript.configure.
121-
122-
fast_linkflags = ['-s']
123-
fast_shlinkflags = pyconfigvar('LDSHARED').split()[1:]
124-
125-
# Specify minimum C++ standard. Allow later standard from sconscript.local.
126-
# In case of multiple `-std` options the last option holds.
127-
env.PrependUnique(CXXFLAGS='-std=c++11', delete_existing=1)
128-
129-
# Need this to avoid missing symbol with boost<1.66
130-
env.PrependUnique(CXXFLAGS=['-DBOOST_ERROR_CODE_HEADER_ONLY'])
131-
132-
# Platform specific intricacies.
133-
if env['PLATFORM'] == 'darwin':
134-
darwin_shlinkflags = [n for n in env['SHLINKFLAGS']
135-
if n != '-dynamiclib']
136-
env.Replace(SHLINKFLAGS=darwin_shlinkflags)
137-
env.AppendUnique(SHLINKFLAGS=['-bundle'])
138-
env.AppendUnique(SHLINKFLAGS=['-undefined', 'dynamic_lookup'])
139-
fast_linkflags[:] = []
140-
141-
# Compiler specific options
142-
if icpc:
143-
# options for Intel C++ compiler on hpc dev-intel07
144-
env.AppendUnique(CCFLAGS=['-w1', '-fp-model', 'precise'])
145-
env.PrependUnique(LIBS=['imf'])
146-
fast_optimflags = ['-fast', '-no-ipo']
120+
if 'PY_VER' in os.environ:
121+
pyversion = os.environ['PY_VER']
122+
else:
123+
pyversion = pyoutput('import sys; print("%i.%i" % sys.version_info[:2])')
124+
125+
if 'CONDA_BUILD' in os.environ and 'PY_VER' in os.environ:
126+
# Messy: if CONDA_BUILD and PY_VER are in the path, we are building a conda package
127+
# using several environment. Make sure python3.X-config points to the destination
128+
# (host) environment
129+
pythonconfig = pjoin(os.environ['PREFIX'], 'bin', 'python%s-config' % os.environ['PY_VER'])
130+
print("Using $PREFIX and $PY_VER to determine python-config pth: %s" % pythonconfig)
131+
xpython = pjoin(os.environ['PREFIX'], 'bin', 'python')
132+
pyversion = os.environ['PY_VER']
133+
else:
134+
pycfgname = 'python%s-config' % (pyversion if pyversion[0] == '3' else '')
135+
# realpath gets the real path if exec is a link (e.g. in a python environment)
136+
xpython = os.path.realpath(env.WhereIs(env['python']))
137+
pybindir = os.path.dirname(xpython)
138+
pythonconfig = pjoin(pybindir, pycfgname)
139+
140+
# for k in sorted(os.environ.keys()):
141+
# print(" ", k, os.environ[k])
142+
143+
if platform.system().lower() == "windows":
144+
# See https://scons.org/faq.html#Linking_on_Windows_gives_me_an_error
145+
env['ENV']['TMP'] = os.environ['TMP']
146+
# the CPPPATH directories are checked by scons dependency scanner
147+
cpppath = getsyspaths('CPLUS_INCLUDE_PATH', 'CPATH')
148+
env.AppendUnique(CPPPATH=cpppath)
149+
# Insert LIBRARY_PATH explicitly because some compilers
150+
# ignore it in the system environment.
151+
env.PrependUnique(LIBPATH=getsyspaths('LIBRARY_PATH'))
152+
if env['prefix'] is not None:
153+
env.Append(CPPPATH=[pjoin(env['prefix'], 'include')])
154+
env.Append(CPPPATH=[pjoin(env['prefix'], 'Library', 'include')])
155+
# Windows conda library paths are a MESS ('lib', 'libs', 'Library\lib'...)
156+
env.Append(LIBPATH=[pjoin(env['prefix'], 'Library', 'lib')])
157+
env.Append(LIBPATH=[pjoin(env['prefix'], 'libs')])
158+
# This disable automated versioned named e.g. libboost_date_time-vc142-mt-s-x64-1_73.lib
159+
# so we can use conda-installed libraries
160+
env.AppendUnique(CPPDEFINES='BOOST_ALL_NO_LIB')
161+
# Prevent the generation of an import lib (.lib) in addition to the dll
162+
# env.AppendUnique(no_import_lib=1)
163+
env.PrependUnique(CCFLAGS=['/Ox', '/EHsc', '/MD'])
164+
env.AppendUnique(CPPDEFINES={'NDEBUG': None})
147165
else:
148-
# g++ options
149-
env.AppendUnique(CCFLAGS=['-Wall'])
150-
fast_optimflags = ['-ffast-math']
151-
152-
# Configure build variants
153-
if env['build'] == 'debug':
154-
env.AppendUnique(CCFLAGS='-g')
155-
elif env['build'] == 'fast':
156-
env.AppendUnique(CCFLAGS=['-O3'] + fast_optimflags)
157-
env.AppendUnique(CPPDEFINES='NDEBUG')
158-
env.AppendUnique(LINKFLAGS=fast_linkflags)
159-
env.AppendUnique(SHLINKFLAGS=fast_shlinkflags)
160-
161-
if env['profile']:
162-
env.AppendUnique(CCFLAGS='-pg')
163-
env.AppendUnique(LINKFLAGS='-pg')
166+
if 'CONDA_BUILD' not in os.environ:
167+
# Verify python-config comes from the same path as the target python.
168+
xpythonconfig = env.WhereIs(pythonconfig)
169+
if os.path.dirname(xpython) != os.path.dirname(xpythonconfig):
170+
print("Inconsistent paths of %r and %r" % (xpython, xpythonconfig))
171+
Exit(1)
172+
# Process the python-config flags here.
173+
env.ParseConfig(pythonconfig + " --cflags")
174+
env.Replace(CCFLAGS=[f for f in env['CCFLAGS'] if good_python_flag(f)])
175+
env.Replace(CPPDEFINES='BOOST_ERROR_CODE_HEADER_ONLY')
176+
# the CPPPATH directories are checked by scons dependency scanner
177+
cpppath = getsyspaths('CPLUS_INCLUDE_PATH', 'CPATH')
178+
env.AppendUnique(CPPPATH=cpppath)
179+
# Insert LIBRARY_PATH explicitly because some compilers
180+
# ignore it in the system environment.
181+
env.PrependUnique(LIBPATH=getsyspaths('LIBRARY_PATH'))
182+
# Add shared libraries.
183+
# Note: ObjCryst and boost_python are added from SConscript.configure.
184+
185+
fast_linkflags = ['-s']
186+
fast_shlinkflags = pyconfigvar('LDSHARED').split()[1:]
187+
188+
# Specify minimum C++ standard. Allow later standard from sconscript.local.
189+
# In case of multiple `-std` options the last option holds.
190+
env.PrependUnique(CXXFLAGS='-std=c++11', delete_existing=1)
191+
192+
# Need this to avoid missing symbol with boost<1.66
193+
env.PrependUnique(CXXFLAGS=['-DBOOST_ERROR_CODE_HEADER_ONLY'])
194+
195+
# Platform specific intricacies.
196+
if env['PLATFORM'] == 'darwin':
197+
darwin_shlinkflags = [n for n in env['SHLINKFLAGS'] if n != '-dynamiclib']
198+
env.Replace(SHLINKFLAGS=darwin_shlinkflags)
199+
env.AppendUnique(SHLINKFLAGS=['-bundle'])
200+
env.AppendUnique(SHLINKFLAGS=['-undefined', 'dynamic_lookup'])
201+
fast_linkflags[:] = []
202+
203+
# Compiler specific options
204+
if icpc:
205+
# options for Intel C++ compiler on hpc dev-intel07
206+
env.AppendUnique(CCFLAGS=['-w1', '-fp-model', 'precise'])
207+
env.PrependUnique(LIBS=['imf'])
208+
fast_optimflags = ['-fast', '-no-ipo']
209+
else:
210+
# g++ options
211+
env.AppendUnique(CCFLAGS=['-Wall', '-fno-strict-aliasing'])
212+
fast_optimflags = ['-ffast-math']
213+
214+
# Configure build variants
215+
if env['build'] == 'debug':
216+
env.AppendUnique(CCFLAGS='-g')
217+
elif env['build'] == 'fast':
218+
env.AppendUnique(CCFLAGS=['-O3'] + fast_optimflags)
219+
env.AppendUnique(CPPDEFINES='NDEBUG')
220+
env.AppendUnique(LINKFLAGS=fast_linkflags)
221+
env.AppendUnique(SHLINKFLAGS=fast_shlinkflags)
222+
223+
if env['profile']:
224+
env.AppendUnique(CCFLAGS='-pg')
225+
env.AppendUnique(LINKFLAGS='-pg')
226+
227+
env.Append(CPPPATH=[pjoin(env['prefix'], 'include')])
228+
env.Append(LIBPATH=[pjoin(env['prefix'], 'lib')])
164229

165230
builddir = env.Dir('build/%s-%s' % (env['build'], platform.machine()))
166231

conda-recipe/build.sh

Lines changed: 0 additions & 9 deletions
This file was deleted.

conda-recipe/conda_build_config.yaml

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,38 @@
11
python:
2+
- 3.10
3+
- 3.9
4+
- 3.8
25
- 3.7
3-
- 3.6
4-
- 3.5
5-
- 2.7
66

77
numpy:
8-
- 1.11
8+
- 1.21
9+
- 1.19
10+
- 1.19
11+
- 1.16
12+
13+
boost:
14+
- 1.78
15+
- 1.78
16+
- 1.78
17+
- 1.73
18+
19+
zip_keys:
20+
- python
21+
- numpy
22+
- boost
923

1024
libobjcryst:
11-
- 2021.1.2
25+
- 2022.1
1226

13-
boost:
14-
- 1.67
27+
c_compiler: # [win]
28+
- vs2019 # [win]
29+
cxx_compiler: # [win]
30+
- vs2019 # [win]
1531

1632
pin_run_as_build:
1733
boost: x.x
34+
35+
# For a local macOS build
36+
CONDA_BUILD_SYSROOT:
37+
- $HOME/dev/SDKs/MacOSX10.9.sdk [osx and not arm64]
38+
- $HOME/dev/SDKs/MacOSX11.0.sdk [arm64]

conda-recipe/meta.yaml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,30 @@ package:
77
source:
88
# git_url: https://github.com/diffpy/pyobjcryst.git
99
git_url: ..
10+
# path: ..
1011

1112
build:
1213
# If this is a new build for the same version, increment the build
1314
# number. If you do not include this key, it defaults to 0.
1415
number: 0
16+
script: {{ PYTHON }} -m pip install . --no-deps -vv
1517

1618
requirements:
1719
build:
1820
- {{ compiler('cxx') }}
19-
host:
21+
- numpy {{ numpy }}
2022
- python {{ python }}
2123
- setuptools
22-
- scons
24+
- git
25+
host:
26+
- python
27+
- pip
2328
- numpy {{ numpy }}
29+
- libobjcryst 2022.1.2
2430
- boost {{ boost }}
25-
- libobjcryst {{ libobjcryst }}
2631

2732
run:
2833
# NOTE libobjcryst is implicitly added by libobjcryst run_exports
29-
- python
30-
- setuptools
3134
- {{ pin_compatible('numpy', min_pin='x.x', max_pin='x') }}
3235
- boost
3336

0 commit comments

Comments
 (0)