#!/bin/bash ## Unreal Engine Container Build script for Third Party Libs ## Copyright Epic Games, Inc. All Rights Reserved. ## This script is expecting to exist in the UE4/Engine/Build/BatchFiles/Linux directory. It will not work correctly ## if you copy it to a different location and run it. # The purpose of this script is to re-build the third party libraries in either # an Ubuntu 14.04 or CentOS 6 container/chroot. This is to maintain compatiblity with older glibc # versions and system libraries. # # It has been tested only on CentOS 7 and Ubuntu 17.10 with the default firewall # and currently only works for matching guest arches. If there are issues with # downloading packages inside the container then this is likely a DNS or # firewall setup problem. # # It uses lxc 1 (lxc net and lxd do not seem available on CentOS 7). echo echo Running Container Build... echo # put ourselves into Source Root directory (two up from location of this script) pushd "`dirname "$0"`/../../../../" ARGS=$* BUILD_ROOT="/mnt/build" INIT_VERSION=1 ### Install Container packages ### InstallPackages() { if [ "$EUID" -ne 0 ]; then echo "Currently unprivileged containers not supported please re-run as root or with sudo." echo "e.g. sudo ./ContainerBuildThridParty.sh $ARGS" exit 1 fi source /etc/os-release # As this script is not generally used for running the editor it is not intended this section would be extended to support # multiple distros. If you are not using a debian or rhel based distro then you must install lxc manually. if [[ $ID_LIKE == *"debian"* ]] || [[ $ID == *"debian"* ]]; then echo "Installing LXC via apt." apt-get install -y lxc qemu-user-static net-tools elif [[ $ID_LIKE == *"fedora"* ]] || [[ $ID == *"fedora"* ]]; then echo "Installing LXC via yum." yum install -y lxc lxc-templates lxc-extra debootstrap libvirt bridge-utils perl qemu-user systemctl start libvirtd fi if ! which lxc-info 1>/dev/null; then echo "Unsupported build environment, please install LXC."; exit 1; fi } ### Set config value SetConfig() { local PARAM=$1 local VALUE=$2 CONFIG_FILE=`GetContainerRoot $CONTAINER_NAME`/../config #echo "Config File: $CONFIG_FILE" if ! grep -l "$PARAM" $CONFIG_FILE 1>/dev/null; then echo "$PARAM = $VALUE" | tee --append $CONFIG_FILE 1>/dev/null else sed -i -e "s/$PARAM[[:blank:]]*=[[:blank:]]*[^\n]*/$PARAM = $VALUE/g" $CONFIG_FILE fi } ### Set network config SetNetworkConfigUbuntuGuest() { local IF=`GetDefaultInterface` local ADDR=$1 local GATEWAY=$2 CONFIG_FILE=`GetContainerRoot $CONTAINER_NAME`/etc/network/interfaces echo "Network Interface File: $CONFIG_FILE" # This is currently specific to an ubuntu trusty guest sed -i -e "s/eth0 inet dhcp/eth0 inet static/g" $CONFIG_FILE echo " address $ADDR" | tee --append $CONFIG_FILE echo " netmask 255.255.255.0" | tee --append $CONFIG_FILE echo " gateway $GATEWAY" | tee --append $CONFIG_FILE CONFIG_FILE=`GetContainerRoot $CONTAINER_NAME`/etc/resolvconf/resolv.conf.d/head echo "Resolv conf File: $CONFIG_FILE" for NAMESERVER in `nmcli device show $IF | grep IP4.DNS | awk '/ /{ print $2 }'`; do echo "nameserver $NAMESERVER" | tee --append $CONFIG_FILE done } ### Set network config SetNetworkConfigCentOSGuest() { local IF=`GetDefaultInterface` local ADDR=$1 local GATEWAY=$2 CONFIG_FILE=`GetContainerRoot $CONTAINER_NAME`/etc/sysconfig/network-scripts/ifcfg-eth0 echo "Network Interface File: $CONFIG_FILE" # This is currently specific to a centos 6 guest echo "DEVICE=eth0" | tee $CONFIG_FILE echo " TYPE=Ethernet" |tee --append $CONFIG_FILE echo " ONBOOT=yes" | tee --append $CONFIG_FILE echo " BOOTPROTO=none" | tee --append $CONFIG_FILE echo " IPADDR=$ADDR" | tee --append $CONFIG_FILE echo " PREFIX=24" | tee --append $CONFIG_FILE echo " GATEWAY=$GATEWAY" | tee --append $CONFIG_FILE echo " IPV4_FAILURE_FATAL=yes" | tee --append $CONFIG_FILE echo " NAME=\"System eth0\"" | tee --append $CONFIG_FILE CONFIG_FILE=`GetContainerRoot $CONTAINER_NAME`/etc/resolv.conf echo "Resolv conf File: $CONFIG_FILE" for NAMESERVER in `nmcli device show $IF | grep IP4.DNS | awk '/ /{ print $2 }'`; do echo "nameserver $NAMESERVER" | tee --append $CONFIG_FILE done } ### Run command as user inside Container RunCommand() { local CONTAINER_NAME=$1 local TARGET_ARCH=$2 shift; shift lxc-attach -n $CONTAINER_NAME -a $TARGET_ARCH --clear-env --keep-var http_proxy --keep-var https_proxy --set-var CONTAINER_BUILD=1 --set-var TARGET_ARCH=$TARGET_ARCH -- su user -c "$*" } ### Run root command inside Container RunRootCommand() { local CONTAINER_NAME=$1 local TARGET_ARCH=$2 shift; shift lxc-attach -n $CONTAINER_NAME -a $TARGET_ARCH --clear-env --keep-var http_proxy --keep-var https_proxy --set-var CONTAINER_BUILD=1 --set-var TARGET_ARCH=$TARGET_ARCH -- $* } ### Get Container Root### GetContainerRoot() { local CONTAINER_NAME=$1 local CONTAINER_ROOT="" CONTAINER_ROOT=`lxc-config lxc.lxcpath`/$CONTAINER_NAME/rootfs echo $CONTAINER_ROOT } ### GetMajorVersion ### GetMajorVersion() { local VERSION=`lxc-info --version` local VERSION_SPLIT=(${VERSION//./ }) echo "${VERSION_SPLIT[0]}" } ### GetMinorVersion ### GetMinorVersion() { local VERSION=`lxc-info --version` local VERSION_SPLIT=(${VERSION//./ }) echo "${VERSION_SPLIT[1]}" } ### GetDefaultInterface ### GetDefaultInterface() { local DEFAULT=`route | grep -m 1 '^default'` local DEFAULT_SPLIT=($DEFAULT) local LENGTH=${#DEFAULT_SPLIT[@]} echo "${DEFAULT_SPLIT[$LENGTH-1]}" } ### Init Network ### InitNetwork() { local IF=`GetDefaultInterface` local LINK_NAME=$1 local IP_ADDR=$2 IP_FORWARD=`cat /proc/sys/net/ipv4/ip_forward` if [ -z $IF ]; then echo "Cannot find default interface"; return fi brctl addbr $LINK_NAME ip addr add $IP_ADDR/24 dev $LINK_NAME ip link set up dev $LINK_NAME echo 1 | tee /proc/sys/net/ipv4/ip_forward > /dev/null iptables -t nat -A POSTROUTING -o $IF -j MASQUERADE iptables -A FORWARD -i $IF -o $LINK_NAME -j ACCEPT iptables -A FORWARD -i $LINK_NAME -o $IF -j ACCEPT # For centos 7 if which firewall-cmd 1>/dev/null; then firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -o $IF -j MASQUERADE > /dev/null firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i $IF -o $LINK_NAME -j ACCEPT > /dev/null firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i $LINK_NAME -o $IF -j ACCEPT > /dev/null fi } ### Cleanup Network ### DestroyNetwork() { local IF=`GetDefaultInterface` local LINK_NAME=$1 local IP_ADDR=$2 local IP_ADDR2=$3 ip addr del $IP_ADDR/24 dev $LINK_NAME ip link set dev $LINK_NAME down brctl delbr $LINK_NAME echo $IP_FORWARD | tee /proc/sys/net/ipv4/ip_forward > /dev/null iptables -t nat -D POSTROUTING -o $IF -j MASQUERADE iptables -D FORWARD -i $IF -o $LINK_NAME -j ACCEPT iptables -D FORWARD -i $LINK_NAME -o $IF -j ACCEPT # For centos 7 if which firewall-cmd 1>/dev/null; then firewall-cmd --direct --remove-rule ipv4 nat POSTROUTING 0 -o $IF -j MASQUERADE > /dev/null firewall-cmd --direct --remove-rule ipv4 filter FORWARD 0 -i $IF -o $LINK_NAME -j ACCEPT > /dev/null firewall-cmd --direct --remove-rule ipv4 filter FORWARD 0 -i $LINK_NAME -o $IF -j ACCEPT > /dev/null fi } ### Init Container ### InitContainer() { local CONTAINER_NAME=$1 local CONTAINER_ROOT="" local CONTAINER_DISTRO=$2 local CONTAINER_VERSION=$3 local TARGET_ARCH=$4 shift; shift; shift; shift local INIT_COMMAND=$* if ! lxc-info -n $CONTAINER_NAME 1>/dev/null; then echo "Creating container" lxc-create -n $CONTAINER_NAME -t download -- -d $CONTAINER_DISTRO -r $CONTAINER_VERSION -a $TARGET_ARCH # Setup lxc networking local NET_KEY="net.0" local ADDR_KEY=".address" if [ `GetMajorVersion` -eq "1" ]; then NET_KEY="network" ADDR_KEY="" fi SetConfig "lxc.$NET_KEY.type" veth SetConfig "lxc.$NET_KEY.flags" down SetConfig "lxc.$NET_KEY.name" "eth0" SetConfig "lxc.$NET_KEY.link" ue4-lxc-br0 SetConfig "lxc.$NET_KEY.ipv4$ADDR_KEY" "172.16.255.2" SetConfig "lxc.$NET_KEY.ipv4.gateway" "172.16.255.1" if [ $CONTAINER_DISTRO == "ubuntu" ]; then SetNetworkConfigUbuntuGuest "172.16.255.2" "172.16.255.1" else SetNetworkConfigCentOSGuest "172.16.255.2" "172.16.255.1" fi local QEMU_ARCH=$TARGET_ARCH if [ $TARGET_ARCH == "armhf" ]; then QEMU_ARCH="arm" elif [ $TARGET_ARCH == "arm64" ]; then QEMU_ARCH="aarch64" fi cp /usr/bin/qemu-$QEMU_ARCH /var/lib/lxc/$CONTAINER_NAME/rootfs/usr/bin/qemu-$QEMU_ARCH-static 2>/dev/null cp /usr/bin/qemu-$QEMU_ARCH-static /var/lib/lxc/$CONTAINER_NAME/rootfs/usr/bin/qemu-$QEMU_ARCH-static 2>/dev/null else echo "Container exists" fi InitNetwork ue4-lxc-br0 172.16.255.1 lxc-start -n $CONTAINER_NAME -d --logfile=$(pwd)/Engine/Build/BatchFiles/Linux/$CONTAINER_NAME.log CONTAINER_ROOT=`GetContainerRoot $CONTAINER_NAME` echo "Container Root: $CONTAINER_ROOT" MountSource $CONTAINER_ROOT echo "Running Container Init..." echo $INIT_COMMAND | tee $CONTAINER_ROOT/var/init.sh 1>/dev/null RunRootCommand $CONTAINER_NAME $TARGET_ARCH sh /var/init.sh if [ -f $CONTAINER_ROOT/var/.uecontainerinit-$INIT_VERSION ]; then echo "Container Init Complete" else echo "Container Init Failed" CloseContainer $CONTAINER_NAME exit 1; fi # Uncomment this if you want to jump in to shell #lxc-attach -n $CONTAINER_NAME -- su user } ### Close Container ### CloseContainer() { local CONTAINER_NAME=$1 CONTAINER_ROOT=`GetContainerRoot $CONTAINER_NAME` UnmountSource $CONTAINER_ROOT lxc-stop -n $CONTAINER_NAME DestroyNetwork ue4-lxc-br0 172.16.255.1 } ### Mount Engine directory into Container ### MountSource() { local CONTAINER_ROOT=$1 mkdir -p $CONTAINER_ROOT/$BUILD_ROOT/ mount --bind `pwd` $CONTAINER_ROOT/$BUILD_ROOT # LXC with SELinux enabled needs this if [ -d /sys/fs/selinux ]; then mkdir -p $CONTAINER_ROOT/sys/fs/selinux mount --bind /sys/fs/selinux $CONTAINER_ROOT/sys/fs/selinux fi } ### Unmount Engine directory ### UnmountSource() { local CONTAINER_ROOT=$1 umount $CONTAINER_ROOT/$BUILD_ROOT if [ -d /sys/fs/selinux ]; then umount $CONTAINER_ROOT/sys/fs/selinux fi mount -o remount,rw /dev/pts } ### Build Third Party libs inside a container for the specified arch ### BuildThirdParty() { local CONTAINER_ROOT="" local CONTAINER_NAME="" local CONTAINER_DISTRO=$1 local CONTAINER_VERSION=$2 local TARGET_ARCH=$3 shift; shift; shift local INIT_COMMAND=$* CONTAINER_NAME=$CONTAINER_DISTRO-$CONTAINER_VERSION-$TARGET_ARCH InitContainer $CONTAINER_NAME $CONTAINER_DISTRO $CONTAINER_VERSION $TARGET_ARCH $INIT_COMMAND ### Exec BuildThirdParty.sh script in Container ### RunCommand $CONTAINER_NAME $TARGET_ARCH $BUILD_ROOT/Engine/Build/BatchFiles/Linux/BuildThirdParty.sh $ARGS CloseContainer $CONTAINER_NAME } # CentOS 6 does not have Wayland included so this needs to be manually updated WAYLAND_BUILD_SCRIPT="cd /tmp; wget https://wayland.freedesktop.org/releases/wayland-1.14.0.tar.xz 1>/dev/null; tar -xvf wayland-1.14.0.tar.xz 1>/dev/null; cd wayland-1.14.0; ./configure --disable-documentation 1>/dev/null; make 1>/dev/null; make install 1>/dev/null; cd ..; wget https://wayland.freedesktop.org/releases/wayland-protocols-1.12.tar.xz 1>/dev/null; tar -xvf wayland-protocols-1.12.tar.xz 1>/dev/null; cd wayland-protocols-1.12; ./configure 1>/dev/null; make 1>/dev/null; make install 1>/dev/null; cd ..; wget http://xkbcommon.org/download/libxkbcommon-0.8.0.tar.xz 1>/dev/null; tar -xvf libxkbcommon-0.8.0.tar.xz 1>/dev/null; cd libxkbcommon-0.8.0; ./configure --disable-x11 1>/dev/null; make 1>/dev/null; make install 1>/dev/null; cd ..; wget https://mesa.freedesktop.org/archive/mesa-17.2.4.tar.xz 1>/dev/null; tar -xvf mesa-17.2.4.tar.xz 1>/dev/null; cd mesa-17.2.4; export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:\$PKG_CONFIG_PATH; sed -i -e 's/2\.4\.\(75\|71\|66\)/2\.4\.65/g' configure.ac; sed -i -e 's/3\.9/3\.3/g' configure.ac; ./autogen.sh --with-platforms=wayland --disable-glx --disable-gbm --with-dri-drivers=swrast; cd src/egl/wayland/wayland-egl; make; make install; cd ..; wget https://www.khronos.org/registry/EGL/api/EGL/egl.h 1>/dev/null; wget https://www.khronos.org/registry/EGL/api/EGL/eglext.h 1>/dev/null; wget https://www.khronos.org/registry/EGL/api/EGL/eglplatform.h 1>/dev/null; mkdir -p /usr/local/include/EGL; cp -r egl*.h /usr/local/include/EGL" # This is to add the current user to the container - does not take into account facl and other permission systems. REAL_UID=`id -u $SUDO_USER` REAL_GID=`id -g $SUDO_USER` if [ $REAL_UID -ne 0 ]; then USER_INIT_COMMAND="set +e; USER_UID=\`id -u user 2>/dev/null\`; USER_GID=\`id -g user 2>/dev/null\`; GROUP_GID=\`getent group user | awk -F: '{print \$3}' 2>/dev/null\`; if [ -z \$USER_UID ]; then useradd -u $REAL_UID user 1>/dev/null; fi; if [ -z \$USER_GID ]; then groupadd -g $REAL_GID user; elif [ ! \$GROUP_GID == $REAL_GID ]; then groupmod -g $REAL_GID user 1>/dev/null; fi; if [ ! \$USER_UID == $REAL_UID ]; then usermod -u $REAL_UID; fi; if [ ! \$USER_GID == $REAL_GID ]; then usermod -g $REAL_GID user 1>/dev/null; fi; set -e"; else USER_INIT_COMMAND="echo stub" fi # Initial container setup for Ubuntu 14.04 UBUNTU_INIT_COMMAND="set -e; if [ -d /sys/fs/selinux ]; then mount -o remount,ro,bind /sys/fs/selinux; fi; if [ ! -f /var/.uecontainerinit-$INIT_VERSION ]; then apt-get install -y bison build-essential cmake git libasound2-dev libegl1-mesa-dev libexpat1-dev libffi-dev libgbm-dev libgles2-mesa-dev libpulse-dev libtool libxcursor-dev libxi-dev libxinerama-dev libxkbcommon-dev libxml2-dev libtool libxrandr-dev libxss-dev llvm llvm-dev mesa-common-dev pkg-config wget x11proto-dri3-dev x11proto-gl-dev x11proto-present-dev x11proto-scrnsaver-dev xutils-dev xz-utils 1>/dev/null; $WAYLAND_BUILD_SCRIPT; fi; touch /var/.uecontainerinit-$INIT_VERSION; $USER_INIT_COMMAND set +e;" # Initial container setup for CentOS 6 CENTOS_INIT_COMMAND="set -e; if [ ! -f /var/.uecontainerinit-$INIT_VERSION ]; then yum install -y wget 1>/dev/null; cd /tmp; wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm 1>/dev/null; rpm -ivh --replacepkgs epel-release-6-8.noarch.rpm 1>/dev/null; yum install -y alsa-lib-devel autoconf bison bzip2 clang cmake coreutils elfutils-libelf-devel expat-devel file flex gcc-c++ gettext git glibc-static gperf help2man libffi-devel libtool libX11-devel libXcursor-devel libXext-devel libXft-devel libXi-devel libXinerama-devel libxml2-devel libXmu-devel libXpm-devel libXrandr-devel libXScrnSaver-devel libxshmfence-devel llvm llvm-devel mesa-libEGL-devel mesa-libGL-devel ncurses-devel patch pkgconfig pulseaudio-libs-devel tar texinfo which xorg-x11-proto-devel xorg-x11-util-macros xz zlib-devel; $WAYLAND_BUILD_SCRIPT; fi; touch /var/.uecontainerinit-$INIT_VERSION; $USER_INIT_COMMAND; set +e;" # Initial container setup for CentOS 7 CENTOS7_INIT_COMMAND="set -e; if [ ! -f /var/.uecontainerinit-$INIT_VERSION ]; then yum install -y epel-release centos-release-scl; yum install -y alsa-lib-devel autoconf bison bzip2 clang cmake3 coreutils elfutils-libelf-devel expat-devel file flex gcc-c++ gettext git glibc-static gperf help2man libffi-devel libtool libX11-devel libXcursor-devel libXext-devel libXft-devel libXi-devel libXinerama-devel libxml2-devel libXmu-devel libXpm-devel libXrandr-devel libXScrnSaver-devel libxshmfence-devel llvm-toolset-7 llvm-toolset-7-llvm-devel make mesa-libEGL-devel mesa-libGL-devel ncurses-devel patch pkgconfig pulseaudio-libs-devel svn tar texinfo wget which xorg-x11-proto-devel xorg-x11-util-macros xz zlib-devel; fi; touch /var/.uecontainerinit-$INIT_VERSION; $USER_INIT_COMMAND; set +e;" InstallPackages # Default - only this builds toolchain BuildThirdParty centos 6 amd64 $CENTOS_INIT_COMMAND # Newer centos for building compiler-rt # BuildThirdParty centos 7 amd64 $CENTOS7_INIT_COMMAND # Others... #BuildThirdParty centos 6 i386 $CENTOS_INIT_COMMAND #BuildThirdParty ubuntu trusty arm64 $UBUNTU_INIT_COMMAND #BuildThirdParty ubuntu trusty armhf $UBUNTU_INIT_COMMAND