diff --git a/7-toolchain b/7-toolchain new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/7-toolchain @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8c100a4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +FROM registry.fedoraproject.org/f27/s2i-core:latest + +ENV SUMMARY="Fedora variant of Red Hat Developer Toolset's C/C++ Toolchain from Software Collections" \ + DESCRIPTION="Platform for building C and C++ applications" \ + NAME=toolchain \ + VERSION=1 \ + ARCH=x86_64 + +LABEL com.redhat.component="$NAME" \ + name="$FGC/$NAME" \ + version="$VERSION" \ + architecture="$ARCH" \ + summary="$SUMMARY" \ + description="$DESCRIPTION" \ + io.k8s.description="$DESCRIPTION" \ + io.k8s.display-name="Fedora variant of Developer Toolset's C/C++ Toolchain from Software Collections" \ + usage="docker run -ti -v /src/app:/opt/app-root/src:z $FGC/$NAME bash" \ + help="docker run IMAGE cat /help.1 | /usr/bin/groff -t -man -ETascii" \ + maintainer="SoftwareCollections.org " + +RUN INSTALL_PKGS="gcc gcc-c++ gcc-gfortran gdb make" && \ + dnf install -y --setopt=tsflags=nodocs $INSTALL_PKGS && \ + rpm -V $INSTALL_PKGS && \ + dnf clean all -y + +# Copy extra files to the image. +COPY ./root/ / + +ENV HOME=/opt/app-root/src \ + PATH=/opt/app-root/src/bin:/opt/app-root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +RUN mkdir -p ${HOME} && \ + groupadd -r default -f -g 1001 && \ + usermod -g default default && \ + chown -R 1001:1001 /opt/app-root /usr/bin/container-entrypoint /usr/bin/usage && \ + chmod u+x /usr/bin/usage && \ + rpm-file-permissions + +USER 1001 + +WORKDIR ${HOME} + +# Set the default CMD to print the usage of the language image +ENTRYPOINT ["container-entrypoint"] +CMD ["usage"] diff --git a/Dockerfile.fedora b/Dockerfile.fedora new file mode 120000 index 0000000..1d1fe94 --- /dev/null +++ b/Dockerfile.fedora @@ -0,0 +1 @@ +Dockerfile \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ab8aaf5 --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +Toolchain For Building C and C++ Applications Docker Image +========================================================== + +Developer Toolchain is part of the Red Hat Software Collections and the Toolchain is a subset of tools usable for building C and C++ applications. Docker container based on Red Hat Software Collection packages is available as rhscl/devtoolset-7-toolchain-rhel7 in registry.access.redhat.com. Docker container based on CentOS packagess is available as centos/devtoolset-7-toolchain-centos7 in the Docker Hub. + + +Description +----------- +Developer Toolset from Red Hat Software Collections provides various tools for C and C++ developers, so they are able to use the Developer Toolset tools without needing to be running a RHEL host. The Toolchain part of the Developer Toolset contains tools for building such applications (GCC compiler for C and C++, GDB, gfortran compiler, etc.). Perftools part contains then tools for debugging and further analysis of the applications (oprofile, valgrind, systemtap, etc.). + + +Usage +----------- +Suppose you have a source for a C application in the `/src/app` directory on the host and that we use the RHEL-based variant (Docker image called rhscl/devtoolset-7-toolchain-rhel7). To build such application you can mount the application sources to the container and run appropriate tools interactively: + +``` +docker run -ti --rm -v /src/app:/opt/app-root/src:z rhscl/devtoolset-7-toolchain-rhel7 bash +bash-4.3$ gcc -o foo -ggdb -g2 foo.c +``` + +That will compile one file from `/src/app` using GCC from container with options `-ggdb -g2`. + +To run `make` non-interactively, run: + +``` +docker run -ti --rm -v $PWD:/opt/app-root/src:z rhscl/devtoolset-7-toolchain-rhel7 make +``` + +That will compile the project from current directory using `make` utility. + +In both cases above user must ensure that the directory where GCC will write data into is writable for the user used inside the container (by default UID 1001). + + +Environment variables and volumes +--------------------------------- +You can set the following mount points by passing the `-v /host:/container` flag to Docker. + +**`/opt/app-root`** + Directory for application sources + + + + +Missing dependencies +-------------------- +It may happen that the program combiled in the container won't have all the dependencies available. In that case, the Developer Toolset Container Image is supposed to be used as a starting point for users, so they do not need to spin their own container from scratch. Creating a new layer on top of the existing container image can be done by writing a new Dockerfile, that will use this image in the FROM clause. For example to install `boost-devel` library as a dependency, create the following Dockerfile: + +``` +FROM rhscl/devtoolset-7-toolchain-rhel7 + +USER 0 +RUN yum install -y --setopt=tsflags=nodocs boost-devel && yum clean all -y +USER 1001 +``` + +Then, build the Dockerfile like this (you need a subscribed RHEL-7 machine to install additional RPMs into the RHEL-based container image): + +``` +docker build -t myorg/devtoolset-7-toolchain-rhel7 . +``` + + +Troubleshooting +--------------- +The error log or standard log if container is run non-interactively is available in the container log. The log can be examined by running: + + docker logs + + +See also +-------- +Dockerfile and other sources for this container image are available on +https://github.com/sclorg/devtoolset-container. +In that repository, Dockerfile for CentOS is called Dockerfile, Dockerfile +for RHEL is called Dockerfile.rhel7. + diff --git a/help.md b/help.md new file mode 120000 index 0000000..42061c0 --- /dev/null +++ b/help.md @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/root/help.1 b/root/help.1 new file mode 100644 index 0000000..625dc61 --- /dev/null +++ b/root/help.1 @@ -0,0 +1,101 @@ +.TH Toolchain For Building C and C++ Applications Docker Image +.PP +Developer Toolchain is part of the Red Hat Software Collections and the Toolchain is a subset of tools usable for building C and C++ applications. Docker container based on Red Hat Software Collection packages is available as rhscl/devtoolset\-7\-toolchain\-rhel7 in registry.access.redhat.com. Docker container based on CentOS packagess is available as centos/devtoolset\-7\-toolchain\-centos7 in the Docker Hub. + +.SH Description +.PP +Developer Toolset from Red Hat Software Collections provides various tools for C and C++ developers, so they are able to use the Developer Toolset tools without needing to be running a RHEL host. The Toolchain part of the Developer Toolset contains tools for building such applications (GCC compiler for C and C++, GDB, gfortran compiler, etc.). Perftools part contains then tools for debugging and further analysis of the applications (oprofile, valgrind, systemtap, etc.). + +.SH Usage +.PP +Suppose you have a source for a C application in the \fB\fC/src/app\fR directory on the host and that we use the RHEL\-based variant (Docker image called rhscl/devtoolset\-7\-toolchain\-rhel7). To build such application you can mount the application sources to the container and run appropriate tools interactively: + +.PP +.RS + +.nf +docker run \-ti \-\-rm \-v /src/app:/opt/app\-root/src:z rhscl/devtoolset\-7\-toolchain\-rhel7 bash +bash\-4.3$ gcc \-o foo \-ggdb \-g2 foo.c + +.fi +.RE + +.PP +That will compile one file from \fB\fC/src/app\fR using GCC from container with options \fB\fC\-ggdb \-g2\fR\&. + +.PP +To run \fB\fCmake\fR non\-interactively, run: + +.PP +.RS + +.nf +docker run \-ti \-\-rm \-v $PWD:/opt/app\-root/src:z rhscl/devtoolset\-7\-toolchain\-rhel7 make + +.fi +.RE + +.PP +That will compile the project from current directory using \fB\fCmake\fR utility. + +.PP +In both cases above user must ensure that the directory where GCC will write data into is writable for the user used inside the container (by default UID 1001). + +.SH Environment variables and volumes +.PP +You can set the following mount points by passing the \fB\fC\-v /host:/container\fR flag to Docker. + +.PP +\fB\fB\fC/opt/app\-root\fR\fP +.br + Directory for application sources + +.SH Missing dependencies +.PP +It may happen that the program combiled in the container won't have all the dependencies available. In that case, the Developer Toolset Container Image is supposed to be used as a starting point for users, so they do not need to spin their own container from scratch. Creating a new layer on top of the existing container image can be done by writing a new Dockerfile, that will use this image in the FROM clause. For example to install \fB\fCboost\-devel\fR library as a dependency, create the following Dockerfile: + +.PP +.RS + +.nf +FROM rhscl/devtoolset\-7\-toolchain\-rhel7 + +USER 0 +RUN yum install \-y \-\-setopt=tsflags=nodocs boost\-devel \&\& yum clean all \-y +USER 1001 + +.fi +.RE + +.PP +Then, build the Dockerfile like this (you need a subscribed RHEL\-7 machine to install additional RPMs into the RHEL\-based container image): + +.PP +.RS + +.nf +docker build \-t myorg/devtoolset\-7\-toolchain\-rhel7 . + +.fi +.RE + +.SH Troubleshooting +.PP +The error log or standard log if container is run non\-interactively is available in the container log. The log can be examined by running: + +.PP +.RS + +.nf +docker logs + +.fi +.RE + +.SH See also +.PP +Dockerfile and other sources for this container image are available on + +\[la]https://github.com/sclorg/devtoolset-container\[ra]\&. +In that repository, Dockerfile for CentOS is called Dockerfile, Dockerfile +for RHEL is called Dockerfile.rhel7. diff --git a/root/opt/app-root/etc/scl_enable b/root/opt/app-root/etc/scl_enable new file mode 100644 index 0000000..a6bb7d1 --- /dev/null +++ b/root/opt/app-root/etc/scl_enable @@ -0,0 +1,6 @@ +# IMPORTANT: Do not add more content to this file unless you know what you are +# doing. This file is sourced everytime the shell session is opened. +# +# This will make scl collection binaries work out of box. +unset BASH_ENV PROMPT_COMMAND ENV +source scl_source enable devtoolset-7 diff --git a/root/usr/bin/container-entrypoint b/root/usr/bin/container-entrypoint new file mode 100755 index 0000000..16c17b9 --- /dev/null +++ b/root/usr/bin/container-entrypoint @@ -0,0 +1,6 @@ +#!/bin/bash + +set -eu +cmd="$1"; shift +exec $cmd "$@" + diff --git a/root/usr/bin/usage b/root/usr/bin/usage new file mode 100644 index 0000000..76b3e63 --- /dev/null +++ b/root/usr/bin/usage @@ -0,0 +1,8 @@ +#!/bin/sh +cat < $TMPDIR/actual-usage + check_result "Exit code is zero" $? 0 + + diff "$THISDIR"/expected-usage $TMPDIR/actual-usage &> /dev/null + check_result "Usage info matches the expected text" $? 0 +} + +function test_sanity_gcc_usage () { + info "Testing 'gcc -v' usage ..." + + docker run --rm $IMAGE_NAME gcc -v &> $TMPDIR/actual-gcc-v + check_result "Exit code is zero" $? 0 + + grep 'gcc version ' $TMPDIR/actual-gcc-v &> /dev/null + check_result "Output contains gcc version" $? 0 +} + +function test_sanity_gdb_usage () { + info "Testing 'gdb -v' usage ..." + + docker run --rm $IMAGE_NAME gdb -v &> $TMPDIR/actual-gdb-v + check_result "Exit code is zero" $? 0 + + grep 'GNU gdb (GDB)' $TMPDIR/actual-gdb-v &> /dev/null + check_result "Output contains gdb version" $? 0 +} + +function test_gcc_compile () { + info "Testing compilation via 'docker run gcc foo.c ..." + + rm -f $TMPDIR/foo $TMPDIR/foo.c + + cat << EOF > $TMPDIR/foo.c +#include + +int main(int argc, char **argv) { printf("Hello world from containerized gcc!\n"); return 0; } +EOF + + docker run --rm -v $TMPDIR:$TMPDIR:z $IMAGE_NAME gcc -o $TMPDIR/foo $TMPDIR/foo.c + check_result "Exit code is zero" $? 0 + + test -e $TMPDIR/foo + check_result "Compiled binary exists" $? 0 + + $TMPDIR/foo &> $TMPDIR/actual-output + check_result "Exit code of compiled binary is zero" $? 0 + + grep "Hello world from containerized gcc!" $TMPDIR/actual-output &> /dev/null + check_result "Compiled binary works" $? 0 +} + +function test_gdb_batch_debug () { + info "Testing debugging via 'docker run gdb -batch ..." + + rm -f $TMPDIR/foo $TMPDIR/foo.c + + cat << EOF > $TMPDIR/foo.c +#include +#include + +int main(int argc, char **argv) +{ + char *s = NULL; + int i; + + for (i = 0; i < INT_MAX; i++) + s[i] = 'f'; + + return 0; +} +EOF + + docker run --rm -v $TMPDIR:$TMPDIR:z $IMAGE_NAME gcc -o $TMPDIR/foo -ggdb -g2 $TMPDIR/foo.c + check_result "Compile test binary" $? 0 + + test -e $TMPDIR/foo + check_result "Test binary exists" $? 0 + + docker run --rm --privileged -v $TMPDIR:$TMPDIR:z $IMAGE_NAME gdb -batch -ex 'run' -ex 'bt' $TMPDIR/foo &> $TMPDIR/actual-output + check_result "Exit code is zero" $? 0 + + grep -q "Program received signal SIGSEGV, Segmentation fault." $TMPDIR/actual-output &> /dev/null + check_result "GDB output informs about segfault" $? 0 + + grep -q "s\[i\] = 'f';" $TMPDIR/actual-output &> /dev/null + check_result "GDB output prints source line" $? 0 +} + +TMPDIR=`mktemp -d` +chmod a+rwx $TMPDIR + +RESULT=0 + +test_docker_run_usage +test_sanity_gcc_usage +test_sanity_gdb_usage +test_gcc_compile +test_gdb_batch_debug + +rm -rf $TMPDIR + +if [ "$RESULT" = "0" ]; then + info "All tests finished" +else + error "Some tests failed" + exit $RESULT +fi diff --git a/test/test-app/Makefile b/test/test-app/Makefile new file mode 100644 index 0000000..d3cd736 --- /dev/null +++ b/test/test-app/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CFLAGS = -g +RM = rm -f + +default: all + +all: hello + +Hello: hello.c + $(CC) $(CFLAGS) -o hello hello.c + +clean veryclean: + $(RM) hello + diff --git a/test/test-app/hello.c b/test/test-app/hello.c new file mode 100644 index 0000000..d52bc2a --- /dev/null +++ b/test/test-app/hello.c @@ -0,0 +1,6 @@ +#include +int main(void) +{ + printf ("Hello from container!\n"); + return 0; +}