diff --git a/.gitignore b/.gitignore index 6717b7f4..98f7ff1f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,9 @@ __pycache__/ .tox/ /.coverage /coverage.xml - .idea/ - sysroot/ - .DS_Store +*.ipynb +*.tags +*.tags1 diff --git a/ros_cross_compile/builders.py b/ros_cross_compile/builders.py index 0fef8c17..8f1a60ea 100644 --- a/ros_cross_compile/builders.py +++ b/ros_cross_compile/builders.py @@ -69,3 +69,36 @@ def __call__( data_collector: DataCollector ): run_emulated_docker_build(docker_client, platform, ros_workspace_dir) + + +def run_cross_compile_docker_build( + docker_client: DockerClient, + platform: Platform, + workspace_path: Path, +) -> None: + docker_client.build_image( + dockerfile_name='build.Dockerfile', + tag=platform.build_image_tag, + ) + + docker_client.run_container( + image_name=platform.build_image_tag, + environment={ + 'OWNER_USER': str(os.getuid()), + 'ROS_DISTRO': platform.ros_distro, + 'TARGET_ARCH': platform.arch, + }, + volumes={ + workspace_path: '/ros_ws', + } + ) + + +class CrossCompileBuild(PipelineStage): + def __init__(self): + super().__init__('cross_compile_build') + + def __call__(self, platform: Platform, docker_client: DockerClient, ros_workspace_dir: Path, + options: PipelineStageConfigOptions, + data_collector: DataCollector): + run_cross_compile_docker_build(docker_client, platform, ros_workspace_dir) diff --git a/ros_cross_compile/dependencies.py b/ros_cross_compile/dependencies.py index 73cab42e..0b638b20 100644 --- a/ros_cross_compile/dependencies.py +++ b/ros_cross_compile/dependencies.py @@ -23,7 +23,7 @@ from ros_cross_compile.pipeline_stages import PipelineStage from ros_cross_compile.pipeline_stages import PipelineStageOptions from ros_cross_compile.platform import Platform -from ros_cross_compile.sysroot_creator import build_internals_dir +from ros_cross_compile.sysroot_creator import build_internals_dir, rosdep_install_script logging.basicConfig(level=logging.INFO) logger = logging.getLogger('Rosdep Gatherer') @@ -34,9 +34,6 @@ _IMG_NAME = 'ros_cross_compile:rosdep' -def rosdep_install_script(platform: Platform) -> Path: - """Construct relative path of the script that installs rosdeps into the sysroot image.""" - return build_internals_dir(platform) / 'install_rosdeps.sh' def gather_rosdeps( diff --git a/ros_cross_compile/docker/build.Dockerfile b/ros_cross_compile/docker/build.Dockerfile new file mode 100644 index 00000000..68c262bd --- /dev/null +++ b/ros_cross_compile/docker/build.Dockerfile @@ -0,0 +1,27 @@ +FROM ubuntu:focal +ENV DEBIAN_FRONTEND=noninteractive + +# Common for all +RUN apt-get update && apt-get install --no-install-recommends -q -y \ + build-essential \ + cmake \ + python3-pip \ + wget + +RUN pip3 install colcon-common-extensions colcon-mixin + +# Specific at the end (layer sharing) +RUN apt-get update && apt-get install --no-install-recommends -q -y \ + gcc-aarch64-linux-gnu \ + g++-aarch64-linux-gnu + +RUN apt-get update && apt-get install -q -y --no-install-recommends rsync + +RUN pip3 install lark-parser numpy + +# Fast and small, no optimization necessary +COPY mixins/ /mixins/ +COPY build_workspace.sh /root +COPY toolchains/ /toolchains/ +WORKDIR /ros_ws +ENTRYPOINT ["/root/build_workspace.sh"] diff --git a/ros_cross_compile/docker/build_workspace.sh b/ros_cross_compile/docker/build_workspace.sh index edb0bf0b..4231c8b2 100755 --- a/ros_cross_compile/docker/build_workspace.sh +++ b/ros_cross_compile/docker/build_workspace.sh @@ -7,16 +7,29 @@ cleanup() { trap 'cleanup' EXIT -mkdir -p /opt/ros/"${ROS_DISTRO}" -touch /opt/ros/"${ROS_DISTRO}"/setup.bash +export SYSROOT=/ros_ws/cc_internals/sysroot +export ROS_WS_INSTALL_PATH=/ros_ws/install_${TARGET_ARCH} +export ROS_WS_BUILD_PATH=/ros_ws/build_${TARGET_ARCH} + +rosdir=${SYSROOT}/opt/ros/${ROS_DISTRO} + +# It's possible that the workspace does not require ROS binary dependencies +# so this could not have been created. Instead of checking, lazily touch it +mkdir -p ${rosdir} +touch ${rosdir}/setup.bash + +export TRIPLE=aarch64-linux-gnu +rsync -a ${SYSROOT}/usr/lib/${TRIPLE}/ /usr/lib/${TRIPLE}/ +rsync -a ${SYSROOT}/usr/include/ /usr/include/ set +ux # shellcheck source=/dev/null -source /opt/ros/"${ROS_DISTRO}"/setup.bash +source ${rosdir}/setup.bash set -ux -colcon build --mixin "${TARGET_ARCH}"-docker \ - --build-base build_"${TARGET_ARCH}" \ - --install-base install_"${TARGET_ARCH}" - +# export MAKEFLAGS="-j1" +colcon build \ + --build-base ${ROS_WS_BUILD_PATH} \ + --install-base ${ROS_WS_INSTALL_PATH} \ + --cmake-args -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_TOOLCHAIN_FILE=/toolchains/${TARGET_ARCH}-gnu.cmake --no-warn-unused-cli # Runs user-provided post-build logic (file is present and empty if it wasn't specified) /user-custom-post-build diff --git a/ros_cross_compile/docker/gather_rosdeps.sh b/ros_cross_compile/docker/gather_rosdeps.sh index 80591dcb..cad070e2 100755 --- a/ros_cross_compile/docker/gather_rosdeps.sh +++ b/ros_cross_compile/docker/gather_rosdeps.sh @@ -49,7 +49,7 @@ grep "apt-get install -y" /tmp/all-deps.sh > /tmp/apt-deps.sh || true # awk notes: # "apt-get", "install", "-y", package_name is the fourth column # ORS=' ' makes the output space-separated instead of newline-separated output -echo "apt-get install -y $(awk '{print $4}' ORS=' ' < /tmp/apt-deps.sh)" >> "${OUT_PATH}" +echo "apt-get install -y --no-install-recommends $(awk '{print $4}' ORS=' ' < /tmp/apt-deps.sh)" >> "${OUT_PATH}" chmod +x "${OUT_PATH}" chown -R "${OWNER_USER}" "${out_dir}" diff --git a/ros_cross_compile/docker/runtime.Dockerfile b/ros_cross_compile/docker/runtime.Dockerfile index fafa9d55..3198f585 100644 --- a/ros_cross_compile/docker/runtime.Dockerfile +++ b/ros_cross_compile/docker/runtime.Dockerfile @@ -8,6 +8,8 @@ FROM $BASE_IMAGE WORKDIR /ros_ws +RUN apt-get update && apt-get install -q -y --no-install-recommends less vim + ARG INSTALL_PATH COPY $INSTALL_PATH/ install diff --git a/ros_cross_compile/docker/sysroot.Dockerfile b/ros_cross_compile/docker/sysroot.Dockerfile index 72bf0922..85d649aa 100644 --- a/ros_cross_compile/docker/sysroot.Dockerfile +++ b/ros_cross_compile/docker/sysroot.Dockerfile @@ -5,71 +5,33 @@ ARG BASE_IMAGE FROM ${BASE_IMAGE} -ARG ROS_VERSION - SHELL ["/bin/bash", "-c"] +ENV DEBIAN_FRONTEND=noninteractive +# Grab the qemu binaries, if any, that were placed in the build context for us COPY bin/* /usr/bin/ -# Set timezone -RUN echo 'Etc/UTC' > /etc/timezone && \ - ln -sf /usr/share/zoneinfo/Etc/UTC /etc/localtime - -RUN apt-get update && apt-get install --no-install-recommends -y \ - tzdata \ - locales \ - && rm -rf /var/lib/apt/lists/* - -# Set locale -RUN echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen && \ - locale-gen && \ - update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 -ENV LANG en_US.UTF-8 -ENV LC_ALL C.UTF-8 - -# Add the ros apt repo +# # Add the ros apt repo RUN apt-get update && apt-get install --no-install-recommends -y \ - dirmngr \ gnupg2 \ lsb-release \ && rm -rf /var/lib/apt/lists/* RUN apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' \ --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 -RUN echo "deb http://packages.ros.org/${ROS_VERSION}/ubuntu `lsb_release -cs` main" \ - > /etc/apt/sources.list.d/${ROS_VERSION}-latest.list +RUN echo "deb http://packages.ros.org/ros/ubuntu `lsb_release -cs` main" \ + >> /etc/apt/sources.list.d/ros-latest.list +RUN echo "deb http://packages.ros.org/ros2/ubuntu `lsb_release -cs` main" \ + >> /etc/apt/sources.list.d/ros-latest.list # ROS dependencies RUN apt-get update && apt-get install --no-install-recommends -y \ - build-essential \ - cmake \ - python3-colcon-common-extensions \ - python3-colcon-mixin \ - python3-dev \ python3-pip \ + libssl-dev \ + symlinks \ && rm -rf /var/lib/apt/lists/* -RUN python3 -m pip install -U \ - setuptools - -# Install some pip packages needed for testing ROS 2 -RUN if [[ "${ROS_VERSION}" == "ros2" ]]; then \ - python3 -m pip install -U \ - flake8 \ - flake8-blind-except \ - flake8-builtins \ - flake8-class-newline \ - flake8-comprehensions \ - flake8-deprecated \ - flake8-docstrings \ - flake8-import-order \ - flake8-quotes \ - pytest-repeat \ - pytest-rerunfailures \ - pytest \ - pytest-cov \ - pytest-runner \ - ; fi +ARG ROS_VERSION # Install Fast-RTPS dependencies for ROS 2 RUN if [[ "${ROS_VERSION}" == "ros2" ]]; then \ @@ -86,13 +48,17 @@ RUN chmod +x ./user-custom-setup && \ ./user-custom-setup && \ rm -rf /var/lib/apt/lists/* +ARG DEPENDENCY_SCRIPT # Use generated rosdep installation script -COPY install_rosdeps.sh . -RUN chmod +x install_rosdeps.sh -RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \ - ./install_rosdeps.sh && \ +COPY ${DEPENDENCY_SCRIPT} . +RUN chmod +x ${DEPENDENCY_SCRIPT} +RUN apt-get update && \ + ./${DEPENDENCY_SCRIPT} && \ rm -rf /var/lib/apt/lists/* +# Make all absolute symlinks in the filesystem relative, so that we can use it for cross-compilation +RUN symlinks -rc / + # Set up build tools for the workspace COPY mixins/ mixins/ RUN colcon mixin add cc_mixin file://$(pwd)/mixins/index.yaml && colcon mixin update cc_mixin diff --git a/ros_cross_compile/docker_client.py b/ros_cross_compile/docker_client.py index a78c85f4..ef332462 100644 --- a/ros_cross_compile/docker_client.py +++ b/ros_cross_compile/docker_client.py @@ -11,21 +11,41 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import io import logging from pathlib import Path +import tarfile from typing import Dict from typing import Optional import docker from docker.utils import kwargs_from_env as docker_kwargs_from_env - logging.basicConfig(level=logging.INFO) logger = logging.getLogger('Docker Client') DEFAULT_COLCON_DEFAULTS_FILE = 'defaults.yaml' +class GeneratorStream(io.RawIOBase): + def __init__(self, generator): + self.leftover = None + self.generator = generator + + def readable(self): + return True + + def readinto(self, b): + try: + length = len(b) # : We're supposed to return at most this much + chunk = self.leftover or next(self.generator) + output, self.leftover = chunk[:length], chunk[length:] + b[:len(output)] = output + return len(output) + except StopIteration: + return 0 # : Indicate EOF + + class DockerClient: """Simplified Docker API for this package's usage patterns.""" @@ -65,6 +85,7 @@ def build_image( """ # Use low-level API to expose logs for image building docker_api = docker.APIClient(**docker_kwargs_from_env()) + logger.info('Sending context to Docker client') log_generator = docker_api.build( path=str(dockerfile_dir) if dockerfile_dir else self._default_docker_dir, dockerfile=dockerfile_name, @@ -119,6 +140,7 @@ def run_container( # Note that the `run` kwarg `stream` is not available # in the version of dockerpy that we are using, so we must detach to live-stream logs # Do not `remove` so that the container can be queried for its exit code after finishing + logger.info("Running docker container of image {}".format(image_name)) container = self._client.containers.run( image=image_name, name=container_name, @@ -146,3 +168,10 @@ def run_container( def get_image_size(self, img_name: str) -> int: return self._client.images.get(img_name).attrs['Size'] + + def export_image_filesystem(self, image_tag: str): + container = self._client.containers.run(image=image_tag, detach=True) + export_generator = container.export() + stream = io.BufferedReader(GeneratorStream(export_generator)) + tar = tarfile.open(fileobj=stream, mode='r|*') + return tar diff --git a/ros_cross_compile/mixins/cross-compile.mixin b/ros_cross_compile/mixins/cross-compile.mixin index bf1408ba..bab77026 100644 --- a/ros_cross_compile/mixins/cross-compile.mixin +++ b/ros_cross_compile/mixins/cross-compile.mixin @@ -1,66 +1,18 @@ build: - aarch64-docker: {} - aarch64-linux: - cmake-args: - - "-DCMAKE_SYSTEM_NAME=Linux" - - "-DCMAKE_SYSTEM_VERSION=1" - - "-DCMAKE_SYSTEM_PROCESSOR=aarch64" - - "-DCMAKE_C_COMPILER=/usr/bin/aarch64-linux-gnu-gcc" - - "-DCMAKE_CXX_COMPILER=/usr/bin/aarch64-linux-gnu-g++" - - "-DCMAKE_SYSROOT=$CC_ROOT/sysroot" - - "-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY" - - "-DCMAKE_FIND_ROOT_PATH=$CC_ROOT/sysroot/root_path:$CC_ROOT/install" - - "-DCMAKE_INSTALL_RPATH=$CC_ROOT/sysroot/opt/ros/$ROS_DISTRO/lib" - - "-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE" - - "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER" - - "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY" - - "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY" - - "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY" - - "-DPYTHON_SOABI=cpython-36m-aarch64-linux-gnu" - - "-DTHREADS_PTHREAD_ARG=0" - - "--no-warn-unused-cli" - arm-linux: - cmake-args: - - "-DCMAKE_SYSTEM_NAME=Linux" - - "-DCMAKE_SYSTEM_VERSION=1" - - "-DCMAKE_SYSTEM_PROCESSOR=armv7l" - - "-DCMAKE_C_COMPILER=/usr/bin/arm-linux-gnueabi-gcc" - - "-DCMAKE_CXX_COMPILER=/usr/bin/arm-linux-gnueabi-g++" - - "-DCMAKE_SYSROOT=$CC_ROOT/sysroot" - - "-DCMAKE_FIND_ROOT_PATH=$CC_ROOT/sysroot/root_path:$CC_ROOT/install" - - "-DCMAKE_INSTALL_RPATH=$CC_ROOT/sysroot/opt/ros/$ROS_DISTRO/lib" - - "-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE" - - "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER" - - "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY" - - "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY" - - "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY" - - "-DPYTHON_SOABI=cpython-36m-arm-linux-gnueabi" - - "-DTHREADS_PTHREAD_ARG=0" - - "--no-warn-unused-cli" - armhf-docker: - cmake-args: - - "-DCMAKE_C_FLAGS=-Wno-psabi" - - "-DCMAKE_CXX_FLAGS=-Wno-psabi" - - "--no-warn-unused-cli" - armhf-linux: - cmake-args: - - "-DCMAKE_SYSTEM_NAME=Linux" - - "-DCMAKE_SYSTEM_VERSION=1" - - "-DCMAKE_SYSTEM_PROCESSOR=arm" - - "-DCMAKE_C_COMPILER=/usr/bin/arm-linux-gnueabihf-gcc" - - "-DCMAKE_CXX_COMPILER=/usr/bin/arm-linux-gnueabihf-g++" - - "-DCMAKE_SYSROOT=$CC_ROOT/sysroot" - - "-DCMAKE_C_FLAGS=-Wno-psabi" - - "-DCMAKE_CXX_FLAGS=-Wno-psabi" - - "-DCMAKE_FIND_ROOT_PATH=$CC_ROOT/sysroot/root_path:$CC_ROOT/install" - - "-DCMAKE_INSTALL_RPATH=$CC_ROOT/sysroot/opt/ros/$ROS_DISTRO/lib" - - "-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE" - - "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER" - - "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY" - - "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY" - - "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY" - - "-DPYTHON_SOABI=cpython-36m-arm-linux-gnueabihf" - - "-DTHREADS_PTHREAD_ARG=0" - - "--no-warn-unused-cli" - x86_64-docker: {} - x86_64-linux: {} + aarch64-docker: {} + aarch64-linux: + cmake-args: + - "-DCMAKE_TOOLCHAIN_FILE=/toolchains/aarch64-gnu.cmake" + - "--no-warn-unused-cli" + armhf-docker: + cmake-args: + - "-DCMAKE_C_FLAGS=-Wno-psabi" + - "-DCMAKE_CXX_FLAGS=-Wno-psabi" + - "--no-warn-unused-cli" + armhf-linux: + cmake-args: + "--no-warn-unused-cli" + ], + } + } +} diff --git a/ros_cross_compile/platform.py b/ros_cross_compile/platform.py index 3ac0ca88..55d8aa51 100644 --- a/ros_cross_compile/platform.py +++ b/ros_cross_compile/platform.py @@ -15,14 +15,18 @@ from typing import NamedTuple from typing import Optional -ArchNameMapping = NamedTuple('ArchNameMapping', [('docker', str), ('qemu', str)]) +ArchNameMapping = NamedTuple( + 'ArchNameMapping', [('docker', str), ('qemu', str), ('target_triple', str)]) # NOTE: when changing any following values, update README.md Supported Targets section ARCHITECTURE_NAME_MAP = { - 'armhf': ArchNameMapping(docker='arm32v7', qemu='arm'), - 'aarch64': ArchNameMapping(docker='arm64v8', qemu='aarch64'), - 'x86_64': ArchNameMapping(docker='', qemu='x86_64'), + 'armhf': ArchNameMapping( + docker='arm32v7', qemu='arm', target_triple='arm-linux-gnueabi'), + 'aarch64': ArchNameMapping( + docker='arm64v8', qemu='aarch64', target_triple='aarch64-linux-gnu'), + 'x86_64': ArchNameMapping( + docker='', qemu='x86_64', target_triple='x86_64-linux-gnu'), } SUPPORTED_ARCHITECTURES = tuple(ARCHITECTURE_NAME_MAP.keys()) @@ -100,6 +104,7 @@ def __init__( else: self._os_distro = ROSDISTRO_OS_MAP[self.ros_distro][self.os_name] native_base = '{}:{}'.format(self.os_name, self.os_distro) + self._native_base = native_base if docker_org: self._docker_target_base = '{}/{}'.format(docker_org, native_base) else: @@ -136,7 +141,15 @@ def __str__(self): @property def sysroot_image_tag(self) -> str: """Generate docker image name and tag.""" - return getpass.getuser() + '/' + str(self) + ':latest' + return 'ros_cross_compile/{}:sysroot'.format(self) + + @property + def build_image_tag(self) -> str: + return 'ros_cross_compile/{}:build'.format(self) + + @property + def build_base_image(self) -> str: + return self._native_base @property def target_base_image(self) -> str: diff --git a/ros_cross_compile/ros_cross_compile.py b/ros_cross_compile/ros_cross_compile.py index e43a62dd..bdde35f2 100644 --- a/ros_cross_compile/ros_cross_compile.py +++ b/ros_cross_compile/ros_cross_compile.py @@ -45,7 +45,8 @@ _PIPELINE = [ CollectDependencyListStage(), CreateSysrootStage(), - EmulatedDockerBuildStage(), + # EmulatedDockerBuildStage(), + CrossCompileBuild(), PackageRuntimeImageStage(), ] diff --git a/ros_cross_compile/sysroot_creator.py b/ros_cross_compile/sysroot_creator.py index 32aa5310..9185e26d 100755 --- a/ros_cross_compile/sysroot_creator.py +++ b/ros_cross_compile/sysroot_creator.py @@ -35,6 +35,11 @@ def build_internals_dir(platform: Platform) -> Path: return Path(INTERNALS_DIR) / str(platform) +def rosdep_install_script(platform: Platform) -> Path: + """Construct relative path of the script that installs rosdeps into the sysroot image.""" + return build_internals_dir(platform) / 'install_rosdeps.sh' + + def _copytree(src: Path, dest: Path) -> None: """Copy contents of directory 'src' into 'dest'.""" copy_tree(str(src), str(dest)) @@ -92,9 +97,11 @@ def prepare_docker_build_environment( package_dir = Path(__file__).parent docker_build_dir = ros_workspace / build_internals_dir(platform) docker_build_dir.mkdir(parents=True, exist_ok=True) + (docker_build_dir.parent / 'COLCON_IGNORE').touch() _copytree(package_dir / 'docker', docker_build_dir) _copytree(package_dir / 'mixins', docker_build_dir / 'mixins') + _copytree(package_dir / 'toolchains', docker_build_dir / 'toolchains') custom_data_dest = docker_build_dir / 'user-custom-data' if custom_data_dir: @@ -110,9 +117,10 @@ def prepare_docker_build_environment( return docker_build_dir -def create_workspace_sysroot_image( +def create_workspace_sysroot( docker_client: DockerClient, platform: Platform, + ros_workspace: Path, ) -> None: """ Create the target platform sysroot image. @@ -122,7 +130,9 @@ def create_workspace_sysroot_image( :param build_context Directory containing all assets needed by sysroot.Dockerfile """ image_tag = platform.sysroot_image_tag + sysroot_destination = (ros_workspace / build_internals_dir(platform)).parent / 'sysroot' + assert_install_rosdep_script_exists(ros_workspace, platform) logger.info('Building sysroot image: %s', image_tag) docker_client.build_image( dockerfile_name='sysroot.Dockerfile', @@ -130,12 +140,22 @@ def create_workspace_sysroot_image( buildargs={ 'BASE_IMAGE': platform.target_base_image, 'ROS_VERSION': platform.ros_version, + 'DEPENDENCY_SCRIPT': 'install_rosdeps.sh', } ) logger.info('Successfully created sysroot docker image: %s', image_tag) - - -class CreateSysrootStage(PipelineStage): + logger.info('Exporting sysroot') + fs = docker_client.export_image_filesystem(image_tag) + logger.info('Extracting sysroot to destination') + try: + shutil.rmtree(str(sysroot_destination)) + except FileNotFoundError: + pass + fs.extractall(sysroot_destination) + fs.close() + + +class CreateSysroot(PipelineStage): """ This stage creates the target platform Docker sysroot image. diff --git a/ros_cross_compile/toolchains/aarch64-gnu.cmake b/ros_cross_compile/toolchains/aarch64-gnu.cmake new file mode 100644 index 00000000..aa1bab52 --- /dev/null +++ b/ros_cross_compile/toolchains/aarch64-gnu.cmake @@ -0,0 +1,34 @@ +#Specific +set(TRIPLE aarch64-linux-gnu) +set(PY_VERSION 38) +set(CMAKE_SYSTEM_PROCESSOR aarch64) + +# Generic +function(require_env name) +if("$ENV{${name}}" STREQUAL "") + message(FATAL_ERROR "Required environment variable ${name} not defined") +endif() +endfunction() + +require_env(SYSROOT) +require_env(ROS_WS_INSTALL_PATH) +require_env(ROS_DISTRO) + +set(CMAKE_SYSTEM_NAME Linux) +SET(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER /usr/bin/${TRIPLE}-gcc) +set(CMAKE_CXX_COMPILER /usr/bin/${TRIPLE}-g++) + +set(CMAKE_SYSROOT $ENV{SYSROOT}) +set(OPENSSL_ROOT_DIR $ENV{SYSROOT}/usr/lib/aarch64-linux-gnu) + +set(CMAKE_FIND_ROOT_PATH $ENV{ROS_WS_INSTALL_PATH}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +set(PYTHON_SOABI cpython-${PY_VERSION}-${TRIPLE}) +set(THREADS_PTHREAD_ARG "0" CACHE STRING "Result from TRY_RUN" FORCE) diff --git a/ros_cross_compile/toolchains/armhf-gnu.cmake b/ros_cross_compile/toolchains/armhf-gnu.cmake new file mode 100644 index 00000000..9298d891 --- /dev/null +++ b/ros_cross_compile/toolchains/armhf-gnu.cmake @@ -0,0 +1,36 @@ +# Specific +set(TRIPLE arm-linux-gnueabihf) +set(PY_VERSION 38) +set(CMAKE_SYSTEM_PROCESSOR arm) +set(CMAKE_C_FLAGS -Wno-psabi) +set(CMAKE_CXX_FLAGS -Wno-psabi) + +# Generic +function(require_env name) +if("$ENV{${name}}" STREQUAL "") + message(FATAL_ERROR "Required environment variable ${name} not defined") +endif() +endfunction() + +require_env(SYSROOT) +require_env(ROS_WS_INSTALL_PATH) +require_env(ROS_DISTRO) + +set(CMAKE_SYSTEM_NAME Linux) +SET(CMAKE_SYSTEM_VERSION 1) + +set(CMAKE_C_COMPILER ${TRIPLE}-gcc) +set(CMAKE_CXX_COMPILER ${TRIPLE}-g++) + +set(CMAKE_SYSROOT $ENV{SYSROOT}) +set(CMAKE_FIND_ROOT_PATH $ENV{ROS_WS_INSTALL_PATH}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_INSTALL_RPATH ${CMAKE_SYSROOT}/opt/ros/${ROS_DISTRO}/lib) + +set(PYTHON_SOABI cpython-${PY_VERSION}-${TRIPLE}) +set(THREADS_PTHREAD_ARG 0) diff --git a/setup.py b/setup.py index 4b421d37..96e6ffbd 100644 --- a/setup.py +++ b/setup.py @@ -51,7 +51,7 @@ package_name: ['docker/*.*', 'mixins/*.*'], }, install_requires=[ - 'docker>=2,<3', + 'docker==4.*', 'setuptools', ], zip_safe=True,