Skip to content

Commit 06d5663

Browse files
authored
Merge pull request #216 from pitmanst/zos
Add support for z/OS compilers; Fixes #215
2 parents 7f70d7d + 88eb8cc commit 06d5663

File tree

3 files changed

+256
-10
lines changed

3 files changed

+256
-10
lines changed

distutils/ccompiler.py

+2
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,7 @@ def mkpath(self, name, mode=0o777):
10601060
# on a cygwin built python we can use gcc like an ordinary UNIXish
10611061
# compiler
10621062
('cygwin.*', 'unix'),
1063+
('zos', 'zos'),
10631064
# OS name mappings
10641065
('posix', 'unix'),
10651066
('nt', 'msvc'),
@@ -1107,6 +1108,7 @@ def get_default_compiler(osname=None, platform=None):
11071108
"Mingw32 port of GNU C Compiler for Win32",
11081109
),
11091110
'bcpp': ('bcppcompiler', 'BCPPCompiler', "Borland C++ Compiler"),
1111+
'zos': ('zosccompiler', 'zOSCCompiler', 'IBM XL C/C++ Compilers'),
11101112
}
11111113

11121114

distutils/command/build_ext.py

+26-10
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,31 @@ def initialize_options(self):
130130
self.user = None
131131
self.parallel = None
132132

133+
@staticmethod
134+
def _python_lib_dir(sysconfig):
135+
"""
136+
Resolve Python's library directory for building extensions
137+
that rely on a shared Python library.
138+
139+
See python/cpython#44264 and python/cpython#48686
140+
"""
141+
if not sysconfig.get_config_var('Py_ENABLE_SHARED'):
142+
return
143+
144+
if sysconfig.python_build:
145+
yield '.'
146+
return
147+
148+
if sys.platform == 'zos':
149+
# On z/OS, a user is not required to install Python to
150+
# a predetermined path, but can use Python portably
151+
installed_dir = sysconfig.get_config_var('base')
152+
lib_dir = sysconfig.get_config_var('platlibdir')
153+
yield os.path.join(installed_dir, lib_dir)
154+
else:
155+
# building third party extensions
156+
yield sysconfig.get_config_var('LIBDIR')
157+
133158
def finalize_options(self): # noqa: C901
134159
from distutils import sysconfig
135160

@@ -231,16 +256,7 @@ def finalize_options(self): # noqa: C901
231256
# building python standard extensions
232257
self.library_dirs.append('.')
233258

234-
# For building extensions with a shared Python library,
235-
# Python's library directory must be appended to library_dirs
236-
# See Issues: #1600860, #4366
237-
if sysconfig.get_config_var('Py_ENABLE_SHARED'):
238-
if not sysconfig.python_build:
239-
# building third party extensions
240-
self.library_dirs.append(sysconfig.get_config_var('LIBDIR'))
241-
else:
242-
# building python standard extensions
243-
self.library_dirs.append('.')
259+
self.library_dirs.extend(self._python_lib_dir(sysconfig))
244260

245261
# The argument parsing will result in self.define being a string, but
246262
# it has to be a list of 2-tuples. All the preprocessor symbols

distutils/zosccompiler.py

+228
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
"""distutils.zosccompiler
2+
3+
Contains the selection of the c & c++ compilers on z/OS. There are several
4+
different c compilers on z/OS, all of them are optional, so the correct
5+
one needs to be chosen based on the users input. This is compatible with
6+
the following compilers:
7+
8+
IBM C/C++ For Open Enterprise Languages on z/OS 2.0
9+
IBM Open XL C/C++ 1.1 for z/OS
10+
IBM XL C/C++ V2.4.1 for z/OS 2.4 and 2.5
11+
IBM z/OS XL C/C++
12+
"""
13+
14+
import os
15+
from .unixccompiler import UnixCCompiler
16+
from . import sysconfig
17+
from .errors import DistutilsExecError, CompileError
18+
19+
_cc_args = {
20+
'ibm-openxl': [
21+
'-m64',
22+
'-fvisibility=default',
23+
'-fzos-le-char-mode=ascii',
24+
'-fno-short-enums',
25+
],
26+
'ibm-xlclang': [
27+
'-q64',
28+
'-qexportall',
29+
'-qascii',
30+
'-qstrict',
31+
'-qnocsect',
32+
'-Wa,asa,goff',
33+
'-Wa,xplink',
34+
'-qgonumber',
35+
'-qenum=int',
36+
'-Wc,DLL',
37+
],
38+
'ibm-xlc': [
39+
'-q64',
40+
'-qexportall',
41+
'-qascii',
42+
'-qstrict',
43+
'-qnocsect',
44+
'-Wa,asa,goff',
45+
'-Wa,xplink',
46+
'-qgonumber',
47+
'-qenum=int',
48+
'-Wc,DLL',
49+
'-qlanglvl=extc99',
50+
],
51+
}
52+
53+
_cxx_args = {
54+
'ibm-openxl': [
55+
'-m64',
56+
'-fvisibility=default',
57+
'-fzos-le-char-mode=ascii',
58+
'-fno-short-enums',
59+
],
60+
'ibm-xlclang': [
61+
'-q64',
62+
'-qexportall',
63+
'-qascii',
64+
'-qstrict',
65+
'-qnocsect',
66+
'-Wa,asa,goff',
67+
'-Wa,xplink',
68+
'-qgonumber',
69+
'-qenum=int',
70+
'-Wc,DLL',
71+
],
72+
'ibm-xlc': [
73+
'-q64',
74+
'-qexportall',
75+
'-qascii',
76+
'-qstrict',
77+
'-qnocsect',
78+
'-Wa,asa,goff',
79+
'-Wa,xplink',
80+
'-qgonumber',
81+
'-qenum=int',
82+
'-Wc,DLL',
83+
'-qlanglvl=extended0x',
84+
],
85+
}
86+
87+
_asm_args = {
88+
'ibm-openxl': ['-fasm', '-fno-integrated-as', '-Wa,--ASA', '-Wa,--GOFF'],
89+
'ibm-xlclang': [],
90+
'ibm-xlc': [],
91+
}
92+
93+
_ld_args = {
94+
'ibm-openxl': [],
95+
'ibm-xlclang': ['-Wl,dll', '-q64'],
96+
'ibm-xlc': ['-Wl,dll', '-q64'],
97+
}
98+
99+
100+
# Python on z/OS is built with no compiler specific options in it's CFLAGS.
101+
# But each compiler requires it's own specific options to build successfully,
102+
# though some of the options are common between them
103+
class zOSCCompiler(UnixCCompiler):
104+
src_extensions = ['.c', '.C', '.cc', '.cxx', '.cpp', '.m', '.s']
105+
_cpp_extensions = ['.cc', '.cpp', '.cxx', '.C']
106+
_asm_extensions = ['.s']
107+
108+
def _get_zos_compiler_name(self):
109+
zos_compiler_names = [
110+
os.path.basename(binary)
111+
for envvar in ('CC', 'CXX', 'LDSHARED')
112+
if (binary := os.environ.get(envvar, None))
113+
]
114+
if len(zos_compiler_names) == 0:
115+
return 'ibm-openxl'
116+
117+
zos_compilers = {}
118+
for compiler in (
119+
'ibm-clang',
120+
'ibm-clang64',
121+
'ibm-clang++',
122+
'ibm-clang++64',
123+
'clang',
124+
'clang++',
125+
'clang-14',
126+
):
127+
zos_compilers[compiler] = 'ibm-openxl'
128+
129+
for compiler in ('xlclang', 'xlclang++', 'njsc', 'njsc++'):
130+
zos_compilers[compiler] = 'ibm-xlclang'
131+
132+
for compiler in ('xlc', 'xlC', 'xlc++'):
133+
zos_compilers[compiler] = 'ibm-xlc'
134+
135+
return zos_compilers.get(zos_compiler_names[0], 'ibm-openxl')
136+
137+
def __init__(self, verbose=0, dry_run=0, force=0):
138+
super().__init__(verbose, dry_run, force)
139+
self.zos_compiler = self._get_zos_compiler_name()
140+
sysconfig.customize_compiler(self)
141+
142+
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
143+
local_args = []
144+
if ext in self._cpp_extensions:
145+
compiler = self.compiler_cxx
146+
local_args.extend(_cxx_args[self.zos_compiler])
147+
elif ext in self._asm_extensions:
148+
compiler = self.compiler_so
149+
local_args.extend(_cc_args[self.zos_compiler])
150+
local_args.extend(_asm_args[self.zos_compiler])
151+
else:
152+
compiler = self.compiler_so
153+
local_args.extend(_cc_args[self.zos_compiler])
154+
local_args.extend(cc_args)
155+
156+
try:
157+
self.spawn(compiler + local_args + [src, '-o', obj] + extra_postargs)
158+
except DistutilsExecError as msg:
159+
raise CompileError(msg)
160+
161+
def runtime_library_dir_option(self, dir):
162+
return '-L' + dir
163+
164+
def link(
165+
self,
166+
target_desc,
167+
objects,
168+
output_filename,
169+
output_dir=None,
170+
libraries=None,
171+
library_dirs=None,
172+
runtime_library_dirs=None,
173+
export_symbols=None,
174+
debug=0,
175+
extra_preargs=None,
176+
extra_postargs=None,
177+
build_temp=None,
178+
target_lang=None,
179+
):
180+
# For a built module to use functions from cpython, it needs to use Pythons
181+
# side deck file. The side deck is located beside the libpython3.xx.so
182+
ldversion = sysconfig.get_config_var('LDVERSION')
183+
if sysconfig.python_build:
184+
side_deck_path = os.path.join(
185+
sysconfig.get_config_var('abs_builddir'),
186+
f'libpython{ldversion}.x',
187+
)
188+
else:
189+
side_deck_path = os.path.join(
190+
sysconfig.get_config_var('installed_base'),
191+
sysconfig.get_config_var('platlibdir'),
192+
f'libpython{ldversion}.x',
193+
)
194+
195+
if os.path.exists(side_deck_path):
196+
if extra_postargs:
197+
extra_postargs.append(side_deck_path)
198+
else:
199+
extra_postargs = [side_deck_path]
200+
201+
# Check and replace libraries included side deck files
202+
if runtime_library_dirs:
203+
for dir in runtime_library_dirs:
204+
for library in libraries[:]:
205+
library_side_deck = os.path.join(dir, f'{library}.x')
206+
if os.path.exists(library_side_deck):
207+
libraries.remove(library)
208+
extra_postargs.append(library_side_deck)
209+
break
210+
211+
# Any required ld args for the given compiler
212+
extra_postargs.extend(_ld_args[self.zos_compiler])
213+
214+
super().link(
215+
target_desc,
216+
objects,
217+
output_filename,
218+
output_dir,
219+
libraries,
220+
library_dirs,
221+
runtime_library_dirs,
222+
export_symbols,
223+
debug,
224+
extra_preargs,
225+
extra_postargs,
226+
build_temp,
227+
target_lang,
228+
)

0 commit comments

Comments
 (0)