Index: libcxx/cmake/caches/s390x-ibm-zos-ascii.cmake =================================================================== --- libcxx/cmake/caches/s390x-ibm-zos-ascii.cmake +++ libcxx/cmake/caches/s390x-ibm-zos-ascii.cmake @@ -11,6 +11,7 @@ set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "") set(LIBCXXABI_ENABLE_STATIC OFF CACHE BOOL "") set(LIBCXXABI_INCLUDE_TESTS OFF CACHE BOOL "") +set(LIBCXXABI_ADDITIONAL_COMPILE_FLAGS "-I $ENV{LLVM_BASE}/zos-unwind" CACHE STRING "") # Target Specific set(LIBCXX_DLL_NAME CRTEQCXS CACHE STRING "") Index: libcxx/cmake/caches/s390x-ibm-zos.cmake =================================================================== --- libcxx/cmake/caches/s390x-ibm-zos.cmake +++ libcxx/cmake/caches/s390x-ibm-zos.cmake @@ -9,6 +9,7 @@ set(LIBCXXABI_ENABLE_SHARED ON CACHE BOOL "") set(LIBCXXABI_ENABLE_STATIC OFF CACHE BOOL "") set(LIBCXXABI_INCLUDE_TESTS ON CACHE BOOL "") +set(LIBCXXABI_ADDITIONAL_COMPILE_FLAGS "-I $ENV{LLVM_BASE}/zos-unwind" CACHE STRING "") # Target Specific set(LIBCXX_DLL_NAME CRTEQCXE CACHE STRING "") Index: libcxx/cmake/caches/s390x32-ibm-zos-ascii.cmake =================================================================== --- libcxx/cmake/caches/s390x32-ibm-zos-ascii.cmake +++ libcxx/cmake/caches/s390x32-ibm-zos-ascii.cmake @@ -11,6 +11,7 @@ set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "") set(LIBCXXABI_ENABLE_STATIC OFF CACHE BOOL "") set(LIBCXXABI_INCLUDE_TESTS OFF CACHE BOOL "") +set(LIBCXXABI_ADDITIONAL_COMPILE_FLAGS "-I $ENV{LLVM_BASE}/zos-unwind" CACHE STRING "") # Target Specific set(LIBCXX_DLL_NAME CRTEHCXS CACHE STRING "") Index: libcxx/cmake/caches/s390x32-ibm-zos.cmake =================================================================== --- libcxx/cmake/caches/s390x32-ibm-zos.cmake +++ libcxx/cmake/caches/s390x32-ibm-zos.cmake @@ -9,6 +9,7 @@ set(LIBCXXABI_ENABLE_SHARED ON CACHE BOOL "") set(LIBCXXABI_ENABLE_STATIC OFF CACHE BOOL "") set(LIBCXXABI_INCLUDE_TESTS ON CACHE BOOL "") +set(LIBCXXABI_ADDITIONAL_COMPILE_FLAGS "-I $ENV{LLVM_BASE}/zos-unwind" CACHE STRING "") # Target Specific set(LIBCXX_DLL_NAME CRTEHCXE CACHE STRING "") Index: libcxx/utils/ci/tso_copy_dataset.sh =================================================================== --- /dev/null +++ libcxx/utils/ci/tso_copy_dataset.sh @@ -0,0 +1,75 @@ +#!/bin/env bash + +#===----------------------------------------------------------------------===## +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +#===----------------------------------------------------------------------===## + +# +# Script to copy the contents of one dataset to another, on z/OS. +# + +end_of_opts=0 +while (( end_of_opts==0 )) +do + case "$1" in + (-T|-B|-X) opts="$opts $1"; opts1="$opts1 $1";; + (-*) opts="$opts $1";; + (*) end_of_opts=1;; + esac + if (( end_of_opts==0 )) + then + shift + fi +done + +if [[ $# -ne 2 ]] +then + echo "usage: $(basename $0) [options] from-ds to-ds" + echo " The options are applied when copying the contents to the target data set" + exit 1 +fi + +from_ds=$1 +to_ds=$2 +alloc_args=$(tsocmd "listds '$from_ds'" |awk '/^--RECFM/ { + getline; + if ($2=="**") + lrecl=0; + else + lrecl=$2+0; + if ($1=="U") { + recfm="U" + space="600,10" + } else if ($1=="FB") { + recfm="F,B" + space="1,1" + } else if ($1=="F") { + recfm="F" + space="1,1" + } + + printf("recfm(%s) dsorg(%s) lrecl(%d) blksize(%d) dsntype(library) space(%s) tracks dir(0)", + recfm, $4, lrecl, $3, space); + }') + +if [[ -z "$alloc_args" ]]; then + exit 2 +fi +tmpdir=${TMPDIR:-/tmp}/cpds.$$ +mkdir -p $tmpdir +echo "Copying $from_ds to $tmpdir" +cp $opts1 "//'$from_ds'" $tmpdir +rc=$? +if [[ $rc -eq 0 ]]; then + echo "Allocating $to_ds if dataset does not exist." + tsocmd "listds '${to_ds}'" | grep -q "\--RECFM-LRECL-BLKSIZE-DSORG" || tso "allocate ds('$to_ds') $alloc_args" && + echo "Copying dataset contents from $tmpdir to $to_ds" + cp $opts $tmpdir/* "//'$to_ds'" + rc=$? +fi +rm -rf $tmpdir +exit $rc Index: libcxx/utils/ci/zos-install-libcxx.sh =================================================================== --- /dev/null +++ libcxx/utils/ci/zos-install-libcxx.sh @@ -0,0 +1,412 @@ +#!/usr/bin/env bash + +#===----------------------------------------------------------------------===## +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +#===----------------------------------------------------------------------===## + +# +# Script to build libc++ & libc++abi on z/OS. +# +set -e + +#============================================================================== +# File scope globals with default values. These can be overriden with +# command-line options. +#============================================================================== +DEBUG=0 +CLEAN=0 +CLOBBER=0 +VERBOSE_OUTPUT="/dev/null" +TARGETS="s390x-ibm-zos" +do_build=0 +do_install=0 +#============================================================================== +# File-scope globals that will be overridden if the user defines them in their +# environment. They can also be overridden with a command-line option. +# Note that these are meant to be more generic variables that make sense to set +# in an LLVM environment. +# All should have an LLVM_ prefix. +#============================================================================== +[[ -z "${LLVM_CMAKE_VARIABLES}" ]] && LLVM_CMAKE_VARIABLES=() +#============================================================================== + +function error() { + printf "ERROR: %s\n" "$*" + exit 1 +} + +function usage() { +cat < Directory containing the newly built runtime + libraries and headers. + --build-hlq Data set prefix including High Level Qualifier to build into. + Default is ${DEFAULT_DATASET_PREFIX} + --buildlib-dir Directory containing the intermediate build products for each target. + --cc The C compiler to use. + --clean Clean build directory. Default is no clean. + --clobber Remove the build and install directories before building. + --cxx The C++ compiler to use. + --install Install the library + --install-dir Directory containing the newly built runtime + libraries and headers. + --install-hlq Data set prefix including High Level Qualifier to build into. + --llvm-root LLVM monorepo directory. + --targets List of targets to build. Default is ${TARGETS}. + --debug Print Configuration and exit." + {-v|--verbose} Verbose output send to /dev/tty device to help debugging build issues. + [-h|--help] Display this help and exit. +EOF +} + +function print_configuration() { + [[ ! -d "${BUILDLIB_DIR}" ]] && mkdir -p "${BUILDLIB_DIR}" + local config_report="${BUILDLIB_DIR}/configuration.txt" + cat > "${config_report}" << EOL +********************************************************************* +* Configuration * +********************************************************************* +* LLVM ROOT: ${LLVM_ROOT} +* BUILDLIB_DIR: ${BUILDLIB_DIR} +* INSTALL DIR: ${INSTALL_DIR} +* BUILD DIR: ${BUILD_DIR} +* C Compiler: ${cc} +* C++ Compiler: ${cxx} +* CMAKE VARS: ${LLVM_CMAKE_VARIABLES[@]} +* BUILD_HLQ: ${BUILD_HLQ} +* CLOBBER: ${CLOBBER} +********************************************************************* + +EOL + + cat "${config_report}" + (( DEBUG == 1 )) && exit + return 0 +} + +while [[ $# -gt 0 ]]; do +case ${1} in + -h|--help) + usage + exit 0 + ;; + --build) + do_build=1 + ;; + --install) + do_install=1 + ;; + --build-hlq) + BUILD_HLQ="${2}" + shift + ;; + --install-hlq) + INSTALL_HLQ="${2}" + shift + ;; + --cc) + CC="${2}" + shift + ;; + --cxx) + CXX="${2}" + shift + ;; + --llvm-root) + LLVM_ROOT="${2}" + shift + ;; + --build-dir) + BUILD_DIR="${2}" + shift + ;; + --buildlib-dir) + BUILDLIB_DIR="${2}" + shift + ;; + --clean) + CLEAN=1 + ;; + --clobber) + CLOBBER=1 + ;; + --install-dir) + INSTALL_DIR="${2}" + shift + ;; + --targets) + TARGETS="${2}" + shift + ;; + --debug) + DEBUG=1 + ;; + -v|--verbose) + VERBOSE_OUTPUT="/dev/tty" + ;; + *) + usage + error "Unknown argument '${1}'" + ;; +esac +shift +done + +[[ "$(uname -s)" != "OS/390" ]] && error "$(basename $0) is intended for z/OS use only." + +REQUIRED_ARGS="LLVM_ROOT CC CXX BUILD_DIR " +[[ $do_build -eq 1 ]] && REQUIRED_ARGS+="BUILDLIB_DIR BUILD_HLQ " +[[ $do_install -eq 1 ]] && REQUIRED_ARGS+="INSTALL_DIR INSTALL_HLQ " + +for arg in $REQUIRED_ARGS ; do + if [ -z ${!arg+x} ]; then + lower="${arg,,}" + error "Missing required argument --${lower//_/-}" + elif [ "${!arg}" == "" ]; then + lower="${arg,,}" + error "Argument to --${lower//_/-} must not be empty" + fi +done + +LLVM_CMAKE_VARIABLES+=('-DCMAKE_C_FLAGS=-mzos-target=zOSV2R3') +LLVM_CMAKE_VARIABLES+=('-DCMAKE_CXX_FLAGS=-mzos-target=zOSV2R3') + +SCEERUN2="${BUILD_HLQ}.SCEERUN2" +SCEERUN="${BUILD_HLQ}.SCEERUN" +SCEELIB="${BUILD_HLQ}.SCEELIB" + +case "$STEPLIB" in +(*${SCEERUN}*) + error "Remove output DS (${SCEERUN}) and/or (${SCEERUN2}) from your STEPLIB before continuing.";; +esac + +function data_set_exists() { + tsocmd "listds '$1'" 2>$VERBOSE_OUTPUT | grep -q "\--RECFM-LRECL-BLKSIZE-DSORG" 1>$VERBOSE_OUTPUT 2>&1 + return $? +} + +function step() { + local separator="=====================================================================" + echo + echo "${separator}" + echo "${1}" + echo "${separator}" +} + +# Check a given parameter and print message and fail if not equal +# i.e., if $1 != $2 then print message, exit +# $1 Return code to check +# $2 Expected value +# $3 Error message to print +# Exit passing original RC (i.e., $1) back +function check_rc_and_fail { + if (( $1 != $2 )); then + echo -e "$3" >&2 + exit $1 + fi +} + +function configure_and_build() { + local libs="libcxx;libcxxabi" + local cc=${CC} + local cxx=${CXX} + + if (( CLOBBER == 1 )); then + rm -rf "${BUILDLIB_DIR}" + data_set_exists "${SCEELIB}" && tso "delete '${SCEELIB}'" + data_set_exists "${SCEERUN2}" && tso "delete '${SCEERUN2}'" + fi + print_configuration + + for target in $TARGETS; do + + (( CLEAN == 1 )) && [[ -e "${BUILDLIB_DIR}/${target}/CMakeCache.txt" ]] && + cmake --build "${BUILDLIB_DIR}/${target}" --target clean + + local cache_file="${LLVM_ROOT}/libcxx/cmake/caches/${target}.cmake" + step "Building ${libs} for ${target}" + [[ ! -d "${BUILDLIB_DIR}/${target}" ]] && mkdir -p "${BUILDLIB_DIR}/${target}" + [[ ! -e "${BUILDLIB_DIR}/${target}/build.ninja" ]] && \ + (cd "${BUILDLIB_DIR}/${target}" && + cmake "${LLVM_ROOT}/runtimes" \ + -C "${cache_file}" \ + -GNinja \ + -DLLVM_ENABLE_RUNTIMES="${libs}" \ + -DCMAKE_C_COMPILER="${cc}" \ + -DCMAKE_CXX_COMPILER="${cxx}" \ + -DCMAKE_INSTALL_PREFIX="${BUILDLIB_DIR}/${target}-install" \ + -DLIBCXX_DATASET_PREFIX:STRING="${BUILD_HLQ}" \ + -DCMAKE_CXX_COMPILER_TARGET="${target}" \ + "${LLVM_CMAKE_VARIABLES[@]}" + ) + local -a targets=( "install-cxxabi" "install-cxx" ) + cmake --build "${BUILDLIB_DIR}/${target}" --target "${targets[@]}" + done +} + +function create_data_sets() { + step "Create library data set SCEERUN2 if not exist." + local SPEC_SCEERUN2="new catalog recfm(u) dsorg(po) lrecl(0) blksize(32760) dsntype(library) space(600,10) tracks dir(0)" + data_set_exists "${SCEERUN2}" || tso -t "allocate ds('${SCEERUN2}') ${SPEC_SCEERUN2}" 2>$VERBOSE_OUTPUT + + step "Create library data set SCEERUN if not exist." + local SPEC_SCEERUN="new catalog recfm(u) dsorg(po) lrecl(0) blksize(32760) dsntype(library) space(2,10) tracks dir(0)" + data_set_exists "${SCEERUN}" || tso -t "allocate ds('${SCEERUN}') ${SPEC_SCEERUN}" 2>$VERBOSE_OUTPUT + + step "Create side deck data set if not exist." + local SPEC_SCEELIB="new catalog recfm(f,b) dsorg(po) lrecl(80) blksize(27920) dsntype(library) space(1,1) tracks dir(0)" + data_set_exists "${SCEELIB}" || tso -t "allocate ds('${SCEELIB}') ${SPEC_SCEELIB}" 2>$VERBOSE_OUTPUT +} + +# Map between target and [dll + sidedeck] name. +function map_dllname_x() { + case "$1" in + (s390x-ibm-zos) + case "$2" in + (libc++) echo "CRTEQCXE CRTDQCXE";; + (libc++abi) echo "CRTEQCXA CRTDQCXA";; + esac + ;; + esac +} + +function map_dllname() { + map_dllname_x $1 $2 |awk '{print $1}' +} + +function map_sidedeck() { + map_dllname_x $1 $2 |awk '{print $2}' +} + +function create_data_sets_and_copy_dlls() { + create_data_sets + + # Special handling to workaround the following by redirecting to VERBOSE_OUTPUT. + # cp -X command empties the log file + step "Copy libraries to SCEERUN2 & SCEELIB." + for target in $TARGETS + do + echo "copy $target libs" + local dir=${BUILDLIB_DIR}/$target/lib + for lib in libc++ libc++abi + do + dll=$(map_dllname $target $lib) + if [[ -z "$dll" ]]; then + echo "Error: no data set name for $lib.so" + exit 1 + fi + x_name=$(map_sidedeck $target $lib) + if [[ -z "$x_name" ]]; then + echo "Error: no data set name for $lib.x" + exit 1 + fi + + cp -X "${dir}/$lib.so" "//'${SCEERUN2}($dll)'" >$VERBOSE_OUTPUT 2>&1 + check_rc_and_fail $? 0 "Failed to copy $target $lib.so to data set... see ${LLVM_LOG}/libcxx-build.log" + + # Put side desks into SCEELIB + cp -B "${dir}/$lib.x" "//'${SCEELIB}($x_name)'" + + # Put side decks into archive in lib dir + create_side_deck "$lib" "$x_name" "${dir}" "${BUILD_DIR}/lib/$target" + done + done +} + +function create_side_deck() { + local dll_name="$1" + local package_name="$2" + local lib_build_dir="$3" + local build_dir="$4" + local archive="/tmp/archive-$$" + local cwd="$(pwd)" + + mkdir "${archive}" + cd "${archive}" + + # Generate side deck magic required by the binder + printf "%-80.80s" '*! IEWBIND INCLUDE' >side_deck_magic.x + + cat side_deck_magic.x "${lib_build_dir}/${dll_name}.x" > ${package_name}.x + + step "Creating side deck ${lib_build_dir}/${dll_name}.a" + ar -ruv "${lib_build_dir}/${dll_name}.a" ${package_name}.x >$VERBOSE_OUTPUT 2>&1 + + + step "Copying side deck ${build_dir}/${dll_name}.a archive." + mkdir -p "${build_dir}" + cp "${lib_build_dir}/${dll_name}.a" "${build_dir}" + + # Cleanup temp files. + cd "${cwd}" + rm -rf ${archive} +} + +function copy_headers() { + # Install the headers by copying the headers from one of the builds into the + # build directory. Headers from both bitmodes should be the same. + + step "Copying the headers to ${BUILD_DIR}/include." + rm -rf "${BUILD_DIR}/include/c++" + mkdir -p "${BUILD_DIR}/include/c++" + for target in $TARGETS + do + if [[ -d ${BUILDLIB_DIR}/$target-install ]]; then + cp -r "${BUILDLIB_DIR}/$target-install/include/c++" "${BUILD_DIR}/include" + return + fi + done +} + +function install_headers { + # Install libcxx headers + step "Copying the headers to ${INSTALL_DIR}/include/c++/v1." + if [[ -d ${BUILD_DIR}/include/c++/v1 ]]; then + rm -rf ${INSTALL_DIR}/include/c++/v1 + mkdir -p ${INSTALL_DIR}/include/c++ + cp -r ${BUILD_DIR}/include/c++/v1 ${INSTALL_DIR}/include/c++ + fi +} + +function install_target_libs { + targ=$1 + mkdir -p "${INSTALL_DIR}/lib/$targ" + for lib in libc++.a libc++abi.a + do + cp "${BUILD_DIR}/lib/$targ/$lib" "${INSTALL_DIR}/lib/$targ/" + done +} + +function install_libs { + # Install libc++.a and libc++abi.a. + # The install location is created during the compiler install step. + if [[ -d "${INSTALL_DIR}/lib" ]]; then + for target in $TARGETS + do + install_target_libs $target + done + fi + + ${LLVM_ROOT}/libcxx/utils/ci/tso_copy_dataset.sh -B ${BUILD_HLQ}.SCEELIB ${INSTALL_HLQ}.SCEELIB + ${LLVM_ROOT}/libcxx/utils/ci/tso_copy_dataset.sh -X -I ${BUILD_HLQ}.SCEERUN2 ${INSTALL_HLQ}.SCEERUN2 +} + +function main() { + + if [[ $do_build -eq 1 ]]; then + configure_and_build + create_data_sets_and_copy_dlls + copy_headers + fi + if [[ $do_install -eq 1 ]]; then + install_headers + install_libs + fi +} + +main "$@"