Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support building shared libraries on z/OS #137

Merged
merged 2 commits into from
Apr 4, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 71 additions & 11 deletions pylib/gyp/generator/make.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ def CalculateVariables(default_variables, params):
default_variables.setdefault("OS", operating_system)
if flavor == "aix":
default_variables.setdefault("SHARED_LIB_SUFFIX", ".a")
elif flavor == "zos":
default_variables.setdefault("SHARED_LIB_SUFFIX", ".x")
else:
default_variables.setdefault("SHARED_LIB_SUFFIX", ".so")
default_variables.setdefault("SHARED_LIB_DIR", "$(builddir)/lib.$(TOOLSET)")
Expand Down Expand Up @@ -248,10 +250,10 @@ def CalculateGeneratorInputInfo(params):
cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)

quiet_cmd_solink = SOLINK($(TOOLSET)) $@
cmd_solink = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS) -Wl,DLL
cmd_solink = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,DLL -o $(patsubst %.x,%.so,$@) $(LD_INPUTS) $(LIBS) && if [ -f $(notdir $@) ]; then /bin/cp $(notdir $@) $@; else true; fi

quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
cmd_solink_module = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS) -Wl,DLL
cmd_solink_module = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
""" # noqa: E501


Expand Down Expand Up @@ -400,6 +402,9 @@ def CalculateGeneratorInputInfo(params):
# send stderr to /dev/null to ignore messages when linking directories.
cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp %(copy_archive_args)s "$<" "$@")

quiet_cmd_symlink = SYMLINK $@
cmd_symlink = ln -sf "$<" "$@"

%(link_commands)s
""" # noqa: E501
r"""
Expand Down Expand Up @@ -981,12 +986,20 @@ def WriteActions(
# libraries, but until everything is made cross-compile safe, also use
# target libraries.
# TODO(piman): when everything is cross-compile safe, remove lib.target
self.WriteLn(
"cmd_%s = LD_LIBRARY_PATH=$(builddir)/lib.host:"
"$(builddir)/lib.target:$$LD_LIBRARY_PATH; "
"export LD_LIBRARY_PATH; "
"%s%s" % (name, cd_action, command)
)
if self.flavor == "zos" or self.flavor == "aix":
self.WriteLn(
"cmd_%s = LIBPATH=$(builddir)/lib.host:"
"$(builddir)/lib.target:$$LIBPATH; "
"export LIBPATH; "
"%s%s" % (name, cd_action, command)
)
else:
self.WriteLn(
"cmd_%s = LD_LIBRARY_PATH=$(builddir)/lib.host:"
"$(builddir)/lib.target:$$LD_LIBRARY_PATH; "
"export LD_LIBRARY_PATH; "
"%s%s" % (name, cd_action, command)
)
self.WriteLn()
outputs = [self.Absolutify(o) for o in outputs]
# The makefile rules are all relative to the top dir, but the gyp actions
Expand Down Expand Up @@ -1480,6 +1493,8 @@ def ComputeOutputBasename(self, spec):
target_prefix = "lib"
if self.flavor == "aix":
target_ext = ".a"
elif self.flavor == "zos":
target_ext = ".x"
else:
target_ext = ".so"
elif self.type == "none":
Expand Down Expand Up @@ -1560,6 +1575,14 @@ def ComputeDeps(self, spec):
# link_deps.extend(spec.get('libraries', []))
return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps))

def GetSharedObjectFromSidedeck(self, sidedeck):
"""Return the shared object files based on sidedeck"""
return re.sub(r"\.x$", ".so", sidedeck)

def GetUnversionedSidedeckFromSidedeck(self, sidedeck):
"""Return the shared object files based on sidedeck"""
return re.sub(r"\.\d+\.x$", ".x", sidedeck)

def WriteDependencyOnExtraOutputs(self, target, extra_outputs):
self.WriteMakeRule(
[self.output_binary],
Expand Down Expand Up @@ -1798,6 +1821,11 @@ def WriteTarget(
part_of_all,
postbuilds=postbuilds,
)
# z/OS has a .so target as well as a sidedeck .x target
if self.flavor == "zos":
self.WriteLn('%s: %s' % (
QuoteSpaces(self.GetSharedObjectFromSidedeck(self.output_binary)),
QuoteSpaces(self.output_binary)))
elif self.type == "loadable_module":
for link_dep in link_deps:
assert " " not in link_dep, (
Expand Down Expand Up @@ -1855,7 +1883,9 @@ def WriteTarget(
else:
file_desc = "executable"
install_path = self._InstallableTargetInstallPath()
installable_deps = [self.output]
installable_deps = []
if self.flavor != "zos":
installable_deps.append(self.output)
if (
self.flavor == "mac"
and "product_dir" not in spec
Expand All @@ -1880,15 +1910,42 @@ def WriteTarget(
comment="Copy this to the %s output path." % file_desc,
part_of_all=part_of_all,
)
installable_deps.append(install_path)
if self.flavor != "zos":
installable_deps.append(install_path)
if self.flavor == 'zos' and self.type == 'shared_library':
# lib.target/libnode.so has a dependency on $(obj).target/libnode.so
self.WriteDoCmd([self.GetSharedObjectFromSidedeck(install_path)],
[self.GetSharedObjectFromSidedeck(self.output)], 'copy',
comment='Copy this to the %s output path.' %
file_desc, part_of_all=part_of_all)
# Create a symlink of libnode.x to libnode.version.x
self.WriteDoCmd([self.GetUnversionedSidedeckFromSidedeck(install_path)],
[install_path], 'symlink',
comment='Symlnk this to the %s output path.' %
file_desc, part_of_all=part_of_all)
# Place libnode.version.so and libnode.x symlink in lib.target dir
installable_deps.append(self.GetSharedObjectFromSidedeck(install_path))
installable_deps.append(
self.GetUnversionedSidedeckFromSidedeck(install_path))
if self.output != self.alias and self.alias != self.target:
self.WriteMakeRule(
[self.alias],
installable_deps,
comment="Short alias for building this %s." % file_desc,
phony=True,
)
if part_of_all:
if self.flavor == 'zos' and self.type == 'shared_library':
# Make sure that .x symlink target is run
self.WriteMakeRule(
['all'],
[
self.GetUnversionedSidedeckFromSidedeck(install_path),
self.GetSharedObjectFromSidedeck(install_path)
],
comment='Add %s to "all" target.' % file_desc,
phony=True,
)
elif part_of_all:
self.WriteMakeRule(
["all"],
[install_path],
Expand Down Expand Up @@ -2184,6 +2241,9 @@ def _InstallableTargetInstallPath(self):
# # Install all shared libs into a common directory (per toolset) for
# # convenient access with LD_LIBRARY_PATH.
# return "$(builddir)/lib.%s/%s" % (self.toolset, self.alias)
if self.flavor == "zos" and self.type == "shared_library":
return "$(builddir)/lib.%s/%s" % (self.toolset, self.alias)

return "$(builddir)/" + self.alias


Expand Down