Skip to content

Commit

Permalink
Add support for z/OS compilers; Fixes pypa#215
Browse files Browse the repository at this point in the history
  • Loading branch information
pitmanst committed Oct 2, 2023
1 parent 5a8ca1b commit 89b3831
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 2 deletions.
2 changes: 2 additions & 0 deletions distutils/ccompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,7 @@ def mkpath(self, name, mode=0o777):
# on a cygwin built python we can use gcc like an ordinary UNIXish
# compiler
('cygwin.*', 'unix'),
('zos', 'zos'),
# OS name mappings
('posix', 'unix'),
('nt', 'msvc'),
Expand Down Expand Up @@ -1103,6 +1104,7 @@ def get_default_compiler(osname=None, platform=None):
"Mingw32 port of GNU C Compiler for Win32",
),
'bcpp': ('bcppcompiler', 'BCPPCompiler', "Borland C++ Compiler"),
'zos': ('zosccompiler', 'zOSCCompiler', 'IBM XL C/C++ Compilers'),
}


Expand Down
11 changes: 9 additions & 2 deletions distutils/command/build_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,15 @@ def finalize_options(self): # noqa: C901
# See Issues: #1600860, #4366
if sysconfig.get_config_var('Py_ENABLE_SHARED'):
if not sysconfig.python_build:
# building third party extensions
self.library_dirs.append(sysconfig.get_config_var('LIBDIR'))
if sys.platform == 'zos':
# On z/OS, a user is not required to install Python to
# a predetermined path, but can use Python portably
installed_dir = sysconfig.get_config_var('base')
lib_dir = sysconfig.get_config_var('platlibdir')
self.library_dirs.append(os.path.join(installed_dir, lib_dir))
else:
# building third party extensions
self.library_dirs.append(sysconfig.get_config_var('LIBDIR'))
else:
# building python standard extensions
self.library_dirs.append('.')
Expand Down
228 changes: 228 additions & 0 deletions distutils/zosccompiler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
"""distutils.zosccompiler
Contains the selection of the c & c++ compilers on z/OS. There are several
different c compilers on z/OS, all of them are optional, so the correct
one needs to be chosen based on the users input. This is compatible with
the following compilers:
IBM C/C++ For Open Enterprise Languages on z/OS 2.0
IBM Open XL C/C++ 1.1 for z/OS
IBM XL C/C++ V2.4.1 for z/OS 2.4 and 2.5
IBM z/OS XL C/C++
"""

import os
from .unixccompiler import UnixCCompiler
from . import sysconfig
from .errors import DistutilsExecError, CompileError

_cc_args = {
'ibm-openxl': [
'-m64',
'-fvisibility=default',
'-fzos-le-char-mode=ascii',
'-fno-short-enums',
],
'ibm-xlclang': [
'-q64',
'-qexportall',
'-qascii',
'-qstrict',
'-qnocsect',
'-Wa,asa,goff',
'-Wa,xplink',
'-qgonumber',
'-qenum=int',
'-Wc,DLL',
],
'ibm-xlc': [
'-q64',
'-qexportall',
'-qascii',
'-qstrict',
'-qnocsect',
'-Wa,asa,goff',
'-Wa,xplink',
'-qgonumber',
'-qenum=int',
'-Wc,DLL',
'-qlanglvl=extc99',
],
}

_cxx_args = {
'ibm-openxl': [
'-m64',
'-fvisibility=default',
'-fzos-le-char-mode=ascii',
'-fno-short-enums',
],
'ibm-xlclang': [
'-q64',
'-qexportall',
'-qascii',
'-qstrict',
'-qnocsect',
'-Wa,asa,goff',
'-Wa,xplink',
'-qgonumber',
'-qenum=int',
'-Wc,DLL',
],
'ibm-xlc': [
'-q64',
'-qexportall',
'-qascii',
'-qstrict',
'-qnocsect',
'-Wa,asa,goff',
'-Wa,xplink',
'-qgonumber',
'-qenum=int',
'-Wc,DLL',
'-qlanglvl=extended0x',
],
}

_asm_args = {
'ibm-openxl': ['-fasm', '-fno-integrated-as', '-Wa,--ASA', '-Wa,--GOFF'],
'ibm-xlclang': [],
'ibm-xlc': [],
}

_ld_args = {
'ibm-openxl': [],
'ibm-xlclang': ['-Wl,dll', '-q64'],
'ibm-xlc': ['-Wl,dll', '-q64'],
}


# Python on z/OS is built with no compiler specific options in it's CFLAGS.
# But each compiler requires it's own specific options to build successfully,
# though some of the options are common between them
class zOSCCompiler(UnixCCompiler):
src_extensions = ['.c', '.C', '.cc', '.cxx', '.cpp', '.m', '.s']
_cpp_extensions = ['.cc', '.cpp', '.cxx', '.C']
_asm_extensions = ['.s']

def _get_zos_compiler_name(self):
zos_compiler_names = [
os.path.basename(binary)
for envvar in ('CC', 'CXX', 'LDSHARED')
if (binary := os.environ.get(envvar, None))
]
if len(zos_compiler_names) == 0:
return 'ibm-openxl'

zos_compilers = {}
for compiler in (
'ibm-clang',
'ibm-clang64',
'ibm-clang++',
'ibm-clang++64',
'clang',
'clang++',
'clang-14',
):
zos_compilers[compiler] = 'ibm-openxl'

for compiler in ('xlclang', 'xlclang++', 'njsc', 'njsc++'):
zos_compilers[compiler] = 'ibm-xlclang'

for compiler in ('xlc', 'xlC', 'xlc++'):
zos_compilers[compiler] = 'ibm-xlc'

return zos_compilers.get(zos_compiler_names[0], 'ibm-openxl')

def __init__(self, verbose=0, dry_run=0, force=0):
super().__init__(verbose, dry_run, force)
self.zos_compiler = self._get_zos_compiler_name()
sysconfig.customize_compiler(self)

def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
local_args = []
if ext in self._cpp_extensions:
compiler = self.compiler_cxx
local_args.extend(_cxx_args[self.zos_compiler])
elif ext in self._asm_extensions:
compiler = self.compiler_so
local_args.extend(_cc_args[self.zos_compiler])
local_args.extend(_asm_args[self.zos_compiler])
else:
compiler = self.compiler_so
local_args.extend(_cc_args[self.zos_compiler])
local_args.extend(cc_args)

try:
self.spawn(compiler + local_args + [src, '-o', obj] + extra_postargs)
except DistutilsExecError as msg:
raise CompileError(msg)

def runtime_library_dir_option(self, dir):
return '-L' + dir

def link(
self,
target_desc,
objects,
output_filename,
output_dir=None,
libraries=None,
library_dirs=None,
runtime_library_dirs=None,
export_symbols=None,
debug=0,
extra_preargs=None,
extra_postargs=None,
build_temp=None,
target_lang=None,
):
# For a built module to use functions from cpython, it needs to use Pythons
# side deck file. The side deck is located beside the libpython3.xx.so
ldversion = sysconfig.get_config_var('LDVERSION')
if sysconfig.python_build:
side_deck_path = os.path.join(
sysconfig.get_config_var('abs_builddir'),
f'libpython{ldversion}.x',
)
else:
side_deck_path = os.path.join(
sysconfig.get_config_var('installed_base'),
sysconfig.get_config_var('platlibdir'),
f'libpython{ldversion}.x',
)

if os.path.exists(side_deck_path):
if extra_postargs:
extra_postargs.append(side_deck_path)
else:
extra_postargs = [side_deck_path]

# Check and replace libraries included side deck files
if runtime_library_dirs:
for dir in runtime_library_dirs:
for library in libraries[:]:
library_side_deck = os.path.join(dir, f'{library}.x')
if os.path.exists(library_side_deck):
libraries.remove(library)
extra_postargs.append(library_side_deck)
break

# Any required ld args for the given compiler
extra_postargs.extend(_ld_args[self.zos_compiler])

super().link(
target_desc,
objects,
output_filename,
output_dir,
libraries,
library_dirs,
runtime_library_dirs,
export_symbols,
debug,
extra_preargs,
extra_postargs,
build_temp,
target_lang,
)

0 comments on commit 89b3831

Please sign in to comment.