Browse code

Package builder: cross compilation support

Cross compilation support in the Package Builder.
This change contains only builder changes and spec files
for cross tools (binutils and gcc)
This change allows to build aarch64 packages on x86_64.

Command invocation:
make packages CROSS_TARGET=aarch64

Change-Id: I4319c68ae1a69c0b8893f798ddf071c3a339e1c7
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/6188
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Anish Swaminathan <anishs@vmware.com>

Alexey Makhalov authored on 2018/11/08 10:14:26
Showing 12 changed files
... ...
@@ -79,6 +79,12 @@ else
79 79
 PACKAGE_BUILD_OPTIONS =
80 80
 endif
81 81
 
82
+ifdef CROSS_TARGET
83
+CROSS_TARGET_FLAGS = --cross-target $(CROSS_TARGET)
84
+else
85
+CROSS_TARGET_FLAGS =
86
+endif
87
+
82 88
 TOOLS_BIN := $(SRCROOT)/tools/bin
83 89
 CONTAIN := $(TOOLS_BIN)/contain
84 90
 ifeq ($(ARCH),x86_64)
... ...
@@ -153,6 +159,7 @@ packages: check-docker-py check-tools $(PHOTON_STAGE) $(PHOTON_PUBLISH_XRPMS) $(
153 153
 		$(PACKAGE_BUILD_OPTIONS) \
154 154
 		$(PHOTON_RPMCHECK_FLAGS) \
155 155
 		$(PHOTON_KAT_BUILD_FLAGS) \
156
+		$(CROSS_TARGET_FLAGS) \
156 157
 		$(PUBLISH_BUILD_DEPENDENCIES) \
157 158
 		$(PACKAGE_WEIGHTS) \
158 159
 		--threads ${THREADS}
... ...
@@ -179,6 +186,7 @@ packages-docker: check-docker-py check-docker-service check-tools $(PHOTON_STAGE
179 179
 		--pkginfo-file $(PHOTON_PKGINFO_FILE) \
180 180
 		$(PACKAGE_BUILD_OPTIONS) \
181 181
 		$(PHOTON_RPMCHECK_FLAGS) \
182
+		$(CROSS_TARGET_FLAGS) \
182 183
 		$(PUBLISH_BUILD_DEPENDENCIES) \
183 184
 		$(PACKAGE_WEIGHTS) \
184 185
 		--threads ${THREADS}
... ...
@@ -269,6 +277,7 @@ tool-chain-stage2: check-tools $(PHOTON_STAGE) $(PHOTON_PUBLISH_RPMS) $(PHOTON_S
269 269
 		$(PACKAGE_BUILD_OPTIONS) \
270 270
 		$(PHOTON_RPMCHECK_FLAGS) \
271 271
 		$(PHOTON_KAT_BUILD_FLAGS) \
272
+		$(CROSS_TARGET_FLAGS) \
272 273
 		--log-path $(PHOTON_LOGS_DIR) \
273 274
 		--threads ${THREADS}
274 275
 
275 276
new file mode 100644
... ...
@@ -0,0 +1,56 @@
0
+Name:    binutils-aarch64-linux-gnu
1
+Summary: Cross Binutils for Aarch64
2
+Version: 2.31.1
3
+Release: 1%{?dist}
4
+License: GPLv2+
5
+URL:     http://www.gnu.org/software/binutils
6
+Group:   System Environment/Base
7
+Vendor:  VMware, Inc.
8
+Distribution: Photon
9
+Source0: https://ftp.gnu.org/gnu/binutils/binutils-%{version}.tar.xz
10
+%define sha1 binutils=3b031410897fe224412f3a6a1b052402d2fbcc6a
11
+BuildArch: x86_64
12
+
13
+%define target_arch aarch64-unknown-linux-gnu
14
+%define sysroot /target-aarch64
15
+
16
+%description
17
+The Binutils package contains a linker, an assembler,
18
+and other tools for handling object files.
19
+
20
+%prep
21
+%setup -q -n binutils-%{version}
22
+
23
+%build
24
+
25
+sh configure \
26
+    --prefix=%{_prefix} \
27
+    --target=%{target_arch} \
28
+    --with-sysroot=%{sysroot} \
29
+    --disable-multilib && \
30
+make configure-host && \
31
+make %{?_smp_mflags}
32
+
33
+%install
34
+make DESTDIR=%{buildroot} install
35
+rm -rf %{buildroot}%{_infodir}
36
+rm -rf %{buildroot}%{_datadir}/locale
37
+
38
+%post   -p /sbin/ldconfig
39
+%postun -p /sbin/ldconfig
40
+
41
+%files
42
+%defattr(-,root,root)
43
+%{_bindir}/*
44
+%{_datadir}/*
45
+%{_prefix}/%{target_arch}/*
46
+
47
+%changelog
48
+* Fri Nov 02 2018 Alexey Makhalov <amakhalov@vmware.com> 2.31.1-1
49
+- Cloned from cross-aarch64-tools.spec
50
+* Thu Nov 1 2018 Sriram Nambakam <snambakam@vmware.com> 1.0.0-3
51
+- Updated versions of cross toolchain components
52
+* Mon Oct 22 2018 Sriram Nambakam <snambakam@vmware.com> 1.0.0-2
53
+- Replace _sysroot definition with sysroot
54
+* Fri Oct 19 2018 Sriram Nambakam <snambakam@vmware.com> 1.0.0
55
+- Initial build. First version
0 56
new file mode 100644
... ...
@@ -0,0 +1,223 @@
0
+%global security_hardening nofortify
1
+
2
+# It needs linux sources only to generate linux-api-headers for
3
+# local glibc build. glibc bits get dropped and will not be packaged
4
+%define linux_kernel_version 4.19.52
5
+%define glibc_version 2.28
6
+
7
+Name:    gcc-aarch64-linux-gnu
8
+Summary: Cross GCC for Aarch64
9
+Version: 7.3.0
10
+Release: 1%{?dist}
11
+Group:   Development/Tools
12
+Vendor:  VMware, Inc.
13
+Distribution: Photon
14
+License: GPLv2+
15
+URL:     http://gcc.gnu.org
16
+Source0: https://ftp.gnu.org/gnu/gcc/gcc-%{version}/gcc-%{version}.tar.xz
17
+%define sha1 gcc=9689b9cae7b2886fdaa08449a26701f095c04e48
18
+Source1: https://www.kernel.org/pub/linux/kernel/v4.x/linux-%{linux_kernel_version}.tar.xz
19
+%define sha1 linux=0fc8eeba8a8a710c95d71f140dfdc4bdff735248
20
+Source2: https://ftp.gnu.org/gnu/glibc/glibc-%{glibc_version}.tar.xz
21
+%define sha1 glibc=ccb5dc9e51a9884df8488f86982439d47b283b2a
22
+Source3: https://ftp.gnu.org/gnu/mpfr/mpfr-4.0.1.tar.gz
23
+%define sha1 mpfr=655e3cf416a0cc9530d9cb3c38dc8839504f0e98
24
+Source4: https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.xz
25
+%define sha1 gmp=9dc6981197a7d92f339192eea974f5eca48fcffe
26
+Source5: https://ftp.gnu.org/gnu/mpc/mpc-1.1.0.tar.gz
27
+%define sha1 mpc=b019d9e1d27ec5fb99497159d43a3164995de2d0
28
+Patch0:   libsanitizer-avoidustat.h-glibc-2.28.patch
29
+Patch1:   PLUGIN_TYPE_CAST.patch
30
+BuildArch: x86_64
31
+Provides: libgcc_s.so.1
32
+Provides: libgcc_s.so.1(GCC_3.0)
33
+Provides: libgcc_s.so.1(GCC_3.3)
34
+Provides: libgcc_s.so.1(GCC_4.2.0)
35
+Provides: libgcc_s.so.1(GLIBC_2.0)
36
+BuildRequires: binutils-aarch64-linux-gnu
37
+Requires: binutils-aarch64-linux-gnu
38
+
39
+%global target_arch aarch64-unknown-linux-gnu
40
+%global target_linux_arch arm64
41
+%global sysroot /target-aarch64
42
+
43
+%description
44
+The GCC package contains the GNU compiler collection,
45
+which includes the C and C++ compilers.
46
+
47
+%prep
48
+%setup -c -q
49
+%setup -T -D -q -a 1
50
+%setup -T -D -q -a 2
51
+%setup -T -D -q -a 3
52
+%setup -T -D -q -a 4
53
+%setup -T -D -q -a 5
54
+
55
+cd gcc-%{version}
56
+%patch0 -p1
57
+%patch1 -p1
58
+ln -sf `ls -1d ../mpfr-*/` mpfr
59
+ln -sf `ls -1d ../gmp-*/` gmp
60
+ln -sf `ls -1d ../mpc-*/` mpc
61
+
62
+# disable no-pie for gcc binaries
63
+sed -i '/^NO_PIE_CFLAGS = /s/@NO_PIE_CFLAGS@//' gcc/Makefile.in
64
+
65
+%build
66
+
67
+# Create usrmove symlinks
68
+mkdir -p %{sysroot}/usr/lib && ln -s usr/lib %{sysroot}/lib
69
+mkdir -p %{sysroot}/usr/bin && ln -s usr/bin %{sysroot}/bin
70
+mkdir -p %{sysroot}/usr/sbin && ln -s usr/sbin %{sysroot}/sbin
71
+
72
+builddir=$RPM_BUILD_DIR/%{name}-%{version}
73
+
74
+###
75
+### Step 1
76
+###
77
+
78
+echo "Step 1. Building Linux headers"
79
+
80
+cd $builddir/linux-%{linux_kernel_version} && \
81
+make mrproper && \
82
+make ARCH=%{target_linux_arch} headers_check && \
83
+make ARCH=%{target_linux_arch} \
84
+     INSTALL_HDR_PATH=%{sysroot}%{_prefix} \
85
+     headers_install
86
+
87
+###
88
+### Step 2
89
+###
90
+
91
+echo "Step 2. Building GCC C compiler"
92
+
93
+mkdir -p $builddir/build-gcc-%{target_arch} && \
94
+cd $builddir/build-gcc-%{target_arch} && \
95
+$builddir/gcc-%{version}/configure \
96
+    --prefix=%{_prefix} \
97
+    --target=%{target_arch} \
98
+    --with-sysroot=%{sysroot} \
99
+    --enable-plugins \
100
+    --enable-languages=c \
101
+    --enable-threads=posix \
102
+    --enable-linker-build-id \
103
+    --disable-multilib && \
104
+make %{?_smp_mflags} all-gcc && \
105
+make install-gcc
106
+
107
+###
108
+### Step 3
109
+###
110
+
111
+echo "Step 3. Building GLIBC headers and C runtime"
112
+
113
+mkdir -p $builddir/build-glibc-%{target_arch} && \
114
+cd $builddir/build-glibc-%{target_arch} && \
115
+$builddir/glibc-%{glibc_version}/configure \
116
+    --prefix=%{_prefix} \
117
+    --libexecdir=/usr/lib/glibc \
118
+    --build=$MACHTYPE \
119
+    --host=%{target_arch} \
120
+    --target=%{target_arch} \
121
+    --with-headers=%{sysroot}/usr/include \
122
+    --disable-multilib \
123
+    libc_cv_forced_unwind=yes && \
124
+make install-bootstrap-headers=yes install-headers install_root=%{sysroot} && \
125
+make %{?_smp_mflags} csu/subdir_lib && \
126
+mkdir -p %{sysroot}/usr/lib && \
127
+install csu/crt1.o csu/crti.o csu/crtn.o \
128
+            %{sysroot}/usr/lib && \
129
+%{target_arch}-gcc \
130
+    -nostdlib \
131
+    -nostartfiles \
132
+    -shared \
133
+    -x c /dev/null \
134
+    -o %{sysroot}/usr/lib/libc.so && \
135
+mkdir -p %{sysroot}/usr/include/gnu && \
136
+touch %{sysroot}/usr/include/gnu/stubs.h
137
+
138
+###
139
+### Step 4
140
+###
141
+
142
+echo "Stage 4. Building GCC compiler support library"
143
+
144
+cd $builddir/build-gcc-%{target_arch} && \
145
+$builddir/gcc-%{version}/configure \
146
+    --prefix=%{_prefix} \
147
+    --target=%{target_arch} \
148
+    --with-sysroot=%{sysroot} \
149
+    --enable-shared \
150
+    --enable-threads=posix \
151
+    --enable-__cxa_atexit \
152
+    --enable-clocale=gnu \
153
+    --enable-languages=c,c++,fortran \
154
+    --disable-multilib \
155
+    --enable-linker-build-id \
156
+    --enable-plugin \
157
+    --with-system-zlib && \
158
+make %{?_smp_mflags} all-target-libgcc && \
159
+make install-target-libgcc
160
+make %{?_smp_mflags} DESTDIR=%{buildroot} install-target-libgcc
161
+
162
+###
163
+### Step 5
164
+###
165
+
166
+echo "Step 5. Building full GLIBC"
167
+
168
+cd $builddir/build-glibc-%{target_arch} && \
169
+make %{?_smp_mflags} && \
170
+make install install_root=%{sysroot}
171
+
172
+###
173
+### Step 6
174
+###
175
+
176
+echo "Step 6. Building full GCC"
177
+
178
+cd $builddir/build-gcc-%{target_arch} && \
179
+make %{?_smp_mflags} all && \
180
+make %{?_smp_mflags} DESTDIR=%{buildroot} install
181
+
182
+
183
+%install
184
+
185
+CROSS_TOOLCHAIN_PKG_CONFIG=%{buildroot}%{_bindir}/%{target_arch}-pkg-config
186
+
187
+cat > $CROSS_TOOLCHAIN_PKG_CONFIG << EOF
188
+#! /bin/sh
189
+
190
+SYSROOT=%{sysroot}
191
+
192
+export PKG_CONFIG_DIR=
193
+export PKG_CONFIG_LIBDIR=\${SYSROOT}/usr/lib/pkgconfig:\${SYSROOT}/usr/share/pkgconfig
194
+export PKG_CONFIG_SYSROOT_DIR=\${SYSROOT}
195
+
196
+exec pkg-config "\$@"
197
+EOF
198
+chmod +x $CROSS_TOOLCHAIN_PKG_CONFIG
199
+
200
+%post   -p /sbin/ldconfig
201
+%postun -p /sbin/ldconfig
202
+
203
+%files
204
+%defattr(-,root,root)
205
+%{_bindir}/*
206
+%{_libdir}/*
207
+%exclude %{_libdir}/debug
208
+%{_lib64dir}/*
209
+%{_libexecdir}/*
210
+%{_datadir}/*
211
+%exclude %{_datadir}/info/dir
212
+%{_prefix}/%{target_arch}/*
213
+
214
+%changelog
215
+* Fri Nov 02 2018 Alexey Makhalov <amakhalov@vmware.com> 7.3.0-1
216
+- Cloned from cross-aarch64-tools.spec
217
+* Thu Nov 1 2018 Sriram Nambakam <snambakam@vmware.com> 1.0.0-3
218
+- Updated versions of cross toolchain components
219
+* Mon Oct 22 2018 Sriram Nambakam <snambakam@vmware.com> 1.0.0-2
220
+- Replace _sysroot definition with sysroot
221
+* Fri Oct 19 2018 Sriram Nambakam <snambakam@vmware.com> 1.0.0
222
+- Initial build. First version
... ...
@@ -53,29 +53,11 @@ class PackageBuilder(object):
53 53
             else:
54 54
                 tUtils.installToolchainRPMS(self.sandbox, self.package, self.version, availablePackages=self.doneList)
55 55
 
56
-            listDependentPackages, listTestPackages, listInstalledPackages, listInstalledRPMs = (
57
-                self._findDependentPackagesAndInstalledRPM(self.sandbox))
56
+            self._installDependencies(constants.buildArch)
57
+            if constants.crossCompiling:
58
+                self._installDependencies(constants.targetArch)
58 59
 
59 60
             pkgUtils = PackageUtils(self.logName, self.logPath)
60
-
61
-            if listDependentPackages:
62
-                self.logger.debug("Installing the build time dependent packages......")
63
-                for pkg in listDependentPackages:
64
-                    packageName, packageVersion = StringUtils.splitPackageNameAndVersion(pkg)
65
-                    self._installPackage(pkgUtils, packageName, packageVersion, self.sandbox, self.logPath,listInstalledPackages, listInstalledRPMs)
66
-                for pkg in listTestPackages:
67
-                    flag = False
68
-                    packageName, packageVersion = StringUtils.splitPackageNameAndVersion(pkg)
69
-                    for depPkg in listDependentPackages:
70
-                        depPackageName, depPackageVersion = StringUtils.splitPackageNameAndVersion(depPkg)
71
-                        if depPackageName == packageName:
72
-                            flag = True
73
-                            break;
74
-                    if flag == False:
75
-                        self._installPackage(pkgUtils, packageName,packageVersion, self.sandbox, self.logPath,listInstalledPackages, listInstalledRPMs)
76
-                pkgUtils.installRPMSInOneShot(self.sandbox)
77
-                self.logger.debug("Finished installing the build time dependent packages....")
78
-
79 61
             pkgUtils.adjustGCCSpecs(self.sandbox, self.package, self.version)
80 62
             pkgUtils.buildRPMSForGivenPackage(self.sandbox, self.package, self.version,
81 63
                                               self.logPath)
... ...
@@ -91,11 +73,37 @@ class PackageBuilder(object):
91 91
         if self.sandbox:
92 92
             self.sandbox.destroy()
93 93
 
94
+    def _installDependencies(self, arch, deps=[]):
95
+        listDependentPackages, listTestPackages, listInstalledPackages, listInstalledRPMs = (
96
+            self._findDependentPackagesAndInstalledRPM(self.sandbox, arch))
97
+
98
+        # PackageUtils should be initialized here - as per arch basis
99
+        # Do not move it to __init__
100
+        pkgUtils = PackageUtils(self.logName, self.logPath)
101
+
102
+        if listDependentPackages:
103
+            self.logger.debug("Installing the build time dependent packages for " + arch)
104
+            for pkg in listDependentPackages:
105
+                packageName, packageVersion = StringUtils.splitPackageNameAndVersion(pkg)
106
+                self._installPackage(pkgUtils, packageName, packageVersion, self.sandbox, self.logPath,listInstalledPackages, listInstalledRPMs, arch)
107
+            for pkg in listTestPackages:
108
+                flag = False
109
+                packageName, packageVersion = StringUtils.splitPackageNameAndVersion(pkg)
110
+                for depPkg in listDependentPackages:
111
+                    depPackageName, depPackageVersion = StringUtils.splitPackageNameAndVersion(depPkg)
112
+                    if depPackageName == packageName:
113
+                        flag = True
114
+                        break;
115
+                if flag == False:
116
+                    self._installPackage(pkgUtils, packageName,packageVersion, self.sandbox, self.logPath,listInstalledPackages, listInstalledRPMs, arch)
117
+            pkgUtils.installRPMSInOneShot(self.sandbox,arch)
118
+            self.logger.debug("Finished installing the build time dependent packages for " + arch)
119
+
94 120
     def _buildPackagePrepareFunction(self, package, version, doneList):
95 121
         self.package = package
96 122
         self.version = version
97 123
         self.logName = "build-" + package + "-" + version
98
-        self.logPath = constants.logPath + "/" + package + "-" + version
124
+        self.logPath = constants.logPath + "/" + package + "-" + version + "." + constants.currentArch
99 125
         if not os.path.isdir(self.logPath):
100 126
             cmdUtils = CommandUtils()
101 127
             cmdUtils.runCommandInShell("mkdir -p " + self.logPath)
... ...
@@ -120,9 +128,9 @@ class PackageBuilder(object):
120 120
         pkg = rpmfile[0:releaseindex]
121 121
         return pkg
122 122
 
123
-    def _findInstalledPackages(self, sandbox):
123
+    def _findInstalledPackages(self, sandbox, arch):
124 124
         pkgUtils = PackageUtils(self.logName, self.logPath)
125
-        listInstalledRPMs = pkgUtils.findInstalledRPMPackages(sandbox)
125
+        listInstalledRPMs = pkgUtils.findInstalledRPMPackages(sandbox, arch)
126 126
         listInstalledPackages = []
127 127
         for installedRPM in listInstalledRPMs:
128 128
             pkg = self._findPackageNameAndVersionFromRPMFile(installedRPM)
... ...
@@ -135,18 +143,24 @@ class PackageBuilder(object):
135 135
         return basePkg in doneList
136 136
 
137 137
 
138
-    def _findRunTimeRequiredRPMPackages(self, rpmPackage, version):
139
-        return SPECS.getData().getRequiresForPackage(rpmPackage, version)
138
+    def _findRunTimeRequiredRPMPackages(self, rpmPackage, version, arch):
139
+        return SPECS.getData(arch).getRequiresForPackage(rpmPackage, version)
140
+
141
+    def _findBuildTimeRequiredPackages(self, arch):
142
+        deps = SPECS.getData(arch).getBuildRequiresForPackage(self.package, self.version)
140 143
 
141
-    def _findBuildTimeRequiredPackages(self):
142
-        return SPECS.getData().getBuildRequiresForPackage(self.package, self.version)
144
+        # Add BuildRequiresNative list
145
+        if constants.crossCompiling and arch == constants.buildArch:
146
+            deps.extend(SPECS.getData(arch).getBuildRequiresNativeForPackage(self.package, self.version))
147
+
148
+        return deps
143 149
 
144 150
     def _findBuildTimeCheckRequiredPackages(self):
145 151
         return SPECS.getData().getCheckBuildRequiresForPackage(self.package, self.version)
146 152
 
147 153
     def _installPackage(self, pkgUtils, package, packageVersion, sandbox, destLogPath,
148
-                        listInstalledPackages, listInstalledRPMs):
149
-        rpmfile = pkgUtils.findRPMFile(package,packageVersion);
154
+                        listInstalledPackages, listInstalledRPMs, arch):
155
+        rpmfile = pkgUtils.findRPMFile(package,packageVersion,arch);
150 156
         if rpmfile is None:
151 157
             self.logger.error("No rpm file found for package: " + package + "-" + packageVersion)
152 158
             raise Exception("Missing rpm file")
... ...
@@ -158,42 +172,46 @@ class PackageBuilder(object):
158 158
         listInstalledPackages.append(pkg)
159 159
         listInstalledRPMs.append(specificRPM)
160 160
         self._installDependentRunTimePackages(pkgUtils, package, packageVersion, sandbox, destLogPath,
161
-                                              listInstalledPackages, listInstalledRPMs)
161
+                                              listInstalledPackages, listInstalledRPMs, arch)
162 162
         noDeps = False
163 163
         if (package in self.mapPackageToCycles or
164 164
                 package in self.listNodepsPackages or
165 165
                 package in constants.noDepsPackageList):
166 166
             noDeps = True
167
-        pkgUtils.prepRPMforInstall(package,packageVersion, noDeps, destLogPath)
167
+        pkgUtils.prepRPMforInstall(package,packageVersion, noDeps, destLogPath, arch)
168 168
 
169 169
     def _installDependentRunTimePackages(self, pkgUtils, package, packageVersion, sandbox, destLogPath,
170
-                                         listInstalledPackages, listInstalledRPMs):
171
-        listRunTimeDependentPackages = self._findRunTimeRequiredRPMPackages(package, packageVersion)
170
+                                         listInstalledPackages, listInstalledRPMs, arch):
171
+        listRunTimeDependentPackages = self._findRunTimeRequiredRPMPackages(package, packageVersion, arch)
172 172
         if listRunTimeDependentPackages:
173 173
             for pkg in listRunTimeDependentPackages:
174 174
                 if pkg in self.mapPackageToCycles:
175 175
                     continue
176 176
                 packageName, packageVersion = StringUtils.splitPackageNameAndVersion(pkg)
177
-                rpmfile = pkgUtils.findRPMFile(packageName, packageVersion)
177
+                rpmfile = pkgUtils.findRPMFile(packageName, packageVersion, arch, True)
178 178
                 if rpmfile is None:
179 179
                     self.logger.error("No rpm file found for package: " + packageName + "-" + packageVersion)
180 180
                     raise Exception("Missing rpm file")
181 181
                 latestPkgRPM = os.path.basename(rpmfile).replace(".rpm", "")
182 182
                 if pkg in listInstalledPackages and latestPkgRPM in listInstalledRPMs:
183 183
                     continue
184
-                self._installPackage(pkgUtils, packageName,packageVersion, sandbox, destLogPath,listInstalledPackages, listInstalledRPMs)
184
+                self._installPackage(pkgUtils, packageName,packageVersion, sandbox, destLogPath,listInstalledPackages, listInstalledRPMs, arch)
185 185
 
186
-    def _findDependentPackagesAndInstalledRPM(self, sandbox):
187
-        listInstalledPackages, listInstalledRPMs = self._findInstalledPackages(sandbox)
186
+    def _findDependentPackagesAndInstalledRPM(self, sandbox, arch):
187
+        listInstalledPackages, listInstalledRPMs = self._findInstalledPackages(sandbox, arch)
188 188
         self.logger.debug(listInstalledPackages)
189
-        listDependentPackages = self._findBuildTimeRequiredPackages()
189
+        if constants.crossCompiling and arch == constants.buildArch:
190
+            listDependentPackages = self._findBuildTimeRequiredPackages(constants.targetArch)
191
+            # TODO remove unsupported by buildArch packages from this list
192
+        else:
193
+            listDependentPackages = self._findBuildTimeRequiredPackages(arch)
190 194
         listTestPackages=[]
191 195
         if constants.rpmCheck and self.package in constants.testForceRPMS:
192 196
             # One time optimization
193 197
             if constants.listMakeCheckRPMPkgWithVersionstoInstall is None:
194 198
                 constants.listMakeCheckRPMPkgWithVersionstoInstall=[]
195 199
                 for package in constants.listMakeCheckRPMPkgtoInstall:
196
-                    version = SPECS.getData().getHighestVersion(package)
200
+                    version = SPECS.getData(arch).getHighestVersion(package)
197 201
                     constants.listMakeCheckRPMPkgWithVersionstoInstall.append(package+"-"+version)
198 202
 
199 203
             listDependentPackages.extend(self._findBuildTimeCheckRequiredPackages())
... ...
@@ -46,18 +46,20 @@ class PackageManager(object):
46 46
 
47 47
     def buildToolChainPackages(self, buildThreads):
48 48
         pkgCount = self.buildToolChain()
49
-        if self.pkgBuildType == "container":
50
-            # Stage 1 build container
51
-            #TODO image name constants.buildContainerImageName
52
-            if pkgCount > 0 or not self.dockerClient.images.list(constants.buildContainerImage):
53
-                self._createBuildContainer(True)
54
-        self.logger.info("Step 2 : Building stage 2 of the toolchain...")
55
-        self.logger.info(constants.listToolChainPackages)
56
-        self.logger.info("")
57
-        self._buildGivenPackages(constants.listToolChainPackages, buildThreads)
58
-        self.logger.info("The entire toolchain is now available")
59
-        self.logger.info(45 * '-')
60
-        self.logger.info("")
49
+        # Stage 2 makes sence only for native tools
50
+        if not constants.crossCompiling:
51
+            if self.pkgBuildType == "container":
52
+                # Stage 1 build container
53
+                #TODO image name constants.buildContainerImageName
54
+                if pkgCount > 0 or not self.dockerClient.images.list(constants.buildContainerImage):
55
+                    self._createBuildContainer(True)
56
+            self.logger.info("Step 2 : Building stage 2 of the toolchain...")
57
+            self.logger.info(constants.listToolChainPackages)
58
+            self.logger.info("")
59
+            self._buildGivenPackages(constants.listToolChainPackages, buildThreads)
60
+            self.logger.info("The entire toolchain is now available")
61
+            self.logger.info(45 * '-')
62
+            self.logger.info("")
61 63
         if self.pkgBuildType == "container":
62 64
             # Stage 2 build container
63 65
             #TODO: rebuild container only if anything in listToolChainPackages was built
... ...
@@ -1,5 +1,4 @@
1 1
 import os
2
-import platform
3 2
 import shutil
4 3
 import re
5 4
 import random
... ...
@@ -39,8 +38,10 @@ class PackageUtils(object):
39 39
         self.noDepsPackagesToInstallInAOneShot = ""
40 40
         self.logfnvalue = None
41 41
 
42
-    def prepRPMforInstall(self, package, version, noDeps=False, destLogPath=None):
43
-        rpmfile = self.findRPMFile(package, version)
42
+    def prepRPMforInstall(self, package, version, noDeps=False, destLogPath=None, arch=None):
43
+        if not arch:
44
+            arch=constants.currentArch
45
+        rpmfile = self.findRPMFile(package, version, arch)
44 46
         if rpmfile is None:
45 47
             self.logger.error("No rpm file found for package: " + package)
46 48
             raise Exception("Missing rpm file")
... ...
@@ -59,7 +60,7 @@ class PackageUtils(object):
59 59
         if "noarch" in rpmfile:
60 60
             rpmDestFile += "noarch/"
61 61
         else:
62
-            rpmDestFile += platform.machine()+"/"
62
+            rpmDestFile += arch+"/"
63 63
         rpmDestFile += rpmName
64 64
 
65 65
         if noDeps:
... ...
@@ -69,8 +70,11 @@ class PackageUtils(object):
69 69
             self.rpmFilesToInstallInAOneShot += " " + rpmDestFile
70 70
             self.packagesToInstallInAOneShot += " " + package
71 71
 
72
-    def installRPMSInOneShot(self, sandbox):
72
+    def installRPMSInOneShot(self, sandbox, arch):
73 73
         rpmInstallcmd = self.rpmBinary + " " + self.installRPMPackageOptions
74
+        if constants.crossCompiling and arch == constants.targetArch:
75
+            rpmInstallcmd += " --ignorearch --noscripts --root /target-" + constants.targetArch
76
+
74 77
         # TODO: Container sandbox might need  + self.forceRpmPackageOptions
75 78
         if self.noDepsRPMFilesToInstallInAOneShot != "":
76 79
             self.logger.debug("Installing nodeps rpms: " +
... ...
@@ -142,12 +146,15 @@ class PackageUtils(object):
142 142
                 CommandUtils().runCommandInShell(cmd, logfn=self.logger.debug)
143 143
         self.logger.debug("RPM build is successful")
144 144
 
145
-    def findRPMFile(self, package,version="*"):
145
+    def findRPMFile(self, package,version="*",arch=None, throw=False):
146
+        if not arch:
147
+            arch=constants.currentArch
148
+
146 149
         cmdUtils = CommandUtils()
147 150
         if version == "*":
148
-                version = SPECS.getData().getHighestVersion(package)
149
-        release = SPECS.getData().getRelease(package, version)
150
-        buildarch=SPECS.getData().getBuildArch(package, version)
151
+                version = SPECS.getData(arch).getHighestVersion(package)
152
+        release = SPECS.getData(arch).getRelease(package, version)
153
+        buildarch=SPECS.getData(arch).getBuildArch(package, version)
151 154
         filename= package + "-" + version + "-" + release + "." + buildarch+".rpm"
152 155
 
153 156
         fullpath = constants.rpmPath + "/" + buildarch + "/" + filename
... ...
@@ -159,18 +166,23 @@ class PackageUtils(object):
159 159
         if os.path.isfile(fullpath):
160 160
             return fullpath
161 161
 
162
+        if throw:
163
+            raise Exception("RPM %s not found" % (filename))
162 164
         return None
163 165
 
164
-    def findInstalledRPMPackages(self, sandbox):
166
+    def findInstalledRPMPackages(self, sandbox, arch):
165 167
         rpms = None
166 168
         def setOutValue(data):
167 169
             nonlocal rpms
168 170
             rpms = data
169 171
         cmd = self.rpmBinary + " " + self.queryRpmPackageOptions
172
+        if constants.crossCompiling and arch == constants.targetArch:
173
+            cmd += " --root /target-" + constants.targetArch
170 174
         sandbox.run(cmd, logfn=setOutValue)
171 175
         return rpms.split()
172 176
 
173 177
     def adjustGCCSpecs(self, sandbox, package, version):
178
+        # TODO: need to harden cross compiller also
174 179
         opt = " " + SPECS.getData().getSecurityHardeningOption(package, version)
175 180
         sandbox.put(self.adjustGCCSpecScript, "/tmp")
176 181
         cmd = "/tmp/" + self.adjustGCCSpecScript + opt
... ...
@@ -257,6 +269,12 @@ class PackageUtils(object):
257 257
 
258 258
         for macro in macros:
259 259
             rpmBuildcmd += ' --define \"%s\"' % macro
260
+
261
+        if constants.crossCompiling:
262
+            rpmBuildcmd += ' --define \"_build %s-unknown-linux-gnu\"' % constants.buildArch
263
+            rpmBuildcmd += ' --define \"_host %s-unknown-linux-gnu\"' % constants.targetArch
264
+            rpmBuildcmd += ' --target='+constants.targetArch+'-unknown-linux-gnu'
265
+
260 266
         rpmBuildcmd += " " + specFile
261 267
 
262 268
         self.logger.debug("Building rpm....")
... ...
@@ -1,5 +1,4 @@
1 1
 import os
2
-import platform
3 2
 import queue
4 3
 import json
5 4
 import operator
... ...
@@ -13,8 +12,8 @@ from SpecParser import SpecParser
13 13
 
14 14
 class SpecData(object):
15 15
 
16
-    def __init__(self, logPath, specFilesPath):
17
-
16
+    def __init__(self, arch, logPath, specFilesPath):
17
+        self.arch = arch
18 18
         self.logger = Logger.getLogger("SpecData", logPath, constants.logLevel)
19 19
 
20 20
         # map default package name to list of SpecObjects. Usually it is just
... ...
@@ -36,12 +35,12 @@ class SpecData(object):
36 36
     # creates corresponding SpecObjects and put them in internal mappings.
37 37
     def _readSpecs(self, specFilesPath):
38 38
         for specFile in self._getListSpecFiles(specFilesPath):
39
-            spec = SpecParser(specFile)
39
+            spec = SpecParser(specFile, self.arch)
40 40
 
41 41
             # skip the specfile if buildarch differs
42 42
             buildarch = spec.packages.get('default').buildarch
43 43
             if (buildarch != "noarch" and
44
-                    platform.machine() != buildarch):
44
+                    buildarch != self.arch):
45 45
                 self.logger.info("skipping spec file: "+str(specFile))
46 46
                 continue
47 47
 
... ...
@@ -136,6 +135,13 @@ class SpecData(object):
136 136
             packages.append(pkg.package)
137 137
         return packages
138 138
 
139
+    def getBuildRequiresNativeForPackage(self, package, version):
140
+        packages=[]
141
+        for pkg in self._getSpecObjField(package, version, field=lambda x : x.buildRequiresNative):
142
+            properVersion = self._getProperVersion(pkg)
143
+            packages.append(pkg.package+"-"+properVersion)
144
+        return packages
145
+
139 146
     def getBuildRequiresForPkg(self, pkg):
140 147
         package, version = StringUtils.splitPackageNameAndVersion(pkg)
141 148
         return self.getBuildRequiresForPackage(package, version)
... ...
@@ -293,19 +299,23 @@ class SpecData(object):
293 293
                 self.logger.debug(self.getPkgNamesFromObj(specObj.installRequires))
294 294
                 self.logger.debug(specObj.installRequiresPackages)
295 295
                 self.logger.debug("security_hardening: " + specObj.securityHardening)
296
+                self.logger.debug("BuildArch: " + str(specObj.buildarch))
296 297
                 self.logger.debug("------------------------------------------------")
297 298
 
298 299
 
299 300
 class SPECS(object):
300 301
     __instance = None
301
-    specData = None
302
+    specData = {}
302 303
 
303 304
     @staticmethod
304
-    def getData():
305
+    def getData(arch=None):
306
+        if not arch:
307
+            arch=constants.currentArch
308
+
305 309
         """ Static access method. """
306 310
         if SPECS.__instance is None:
307 311
             SPECS()
308
-        return SPECS.__instance.specData
312
+        return SPECS.__instance.specData[arch]
309 313
 
310 314
     def __init__(self):
311 315
         """ Virtually private constructor. """
... ...
@@ -319,7 +329,7 @@ class SPECS(object):
319 319
         # Preparse some files
320 320
 
321 321
         # adding kernelversion rpm macro
322
-        spec = SpecParser(constants.specPath + "/linux/linux.spec")
322
+        spec = SpecParser(constants.specPath + "/linux/linux.spec", constants.buildArch)
323 323
         defPkg = spec.packages.get('default')
324 324
         kernelversion = defPkg.version
325 325
         constants.addMacro("KERNEL_VERSION", kernelversion)
... ...
@@ -338,5 +348,11 @@ class SPECS(object):
338 338
             constants.addMacro("kernelsubrelease", kernelsubrelease)
339 339
 
340 340
         # Full parsing
341
-        self.specData = SpecData(constants.logPath, constants.specPath)
342
-
341
+        self.specData[constants.buildArch] = SpecData(constants.buildArch,
342
+                                                      constants.logPath,
343
+                                                      constants.specPath)
344
+
345
+        if constants.buildArch != constants.targetArch:
346
+            self.specData[constants.targetArch] = SpecData(constants.targetArch,
347
+                                                           constants.logPath,
348
+                                                           constants.specPath)
... ...
@@ -1,6 +1,5 @@
1 1
 # pylint: disable=invalid-name,missing-docstring
2 2
 import re
3
-import platform
4 3
 from StringUtils import StringUtils
5 4
 from SpecStructures import dependentPackageData, Package, SpecObject
6 5
 from constants import constants
... ...
@@ -15,7 +14,8 @@ class SpecParser(object):
15 15
             self.position = -1
16 16
             self.endposition = -1
17 17
 
18
-    def __init__(self, specfile):
18
+    def __init__(self, specfile, arch):
19
+        self.arch = arch
19 20
         self.cleanMacro = None
20 21
         self.prepMacro = None
21 22
         self.buildMacro = None
... ...
@@ -26,6 +26,7 @@ class SpecParser(object):
26 26
         self.specAdditionalContent = ""
27 27
         self.globalSecurityHardening = ""
28 28
         self.defs = {}
29
+        self.defs["_arch"] = arch
29 30
         self.conditionalCheckMacroEnabled = False
30 31
         self.macro_pattern = re.compile(r'%{(\S+?)\}')
31 32
         self.specfile = specfile
... ...
@@ -33,7 +34,7 @@ class SpecParser(object):
33 33
         self._parseSpecFile()
34 34
 
35 35
     def _parseSpecFile(self):
36
-        self.packages["default"] = Package()
36
+        self.packages["default"] = Package(self.arch)
37 37
         currentPkg = "default"
38 38
         with open(self.specfile) as specFile:
39 39
             lines = specFile.readlines()
... ...
@@ -42,7 +43,7 @@ class SpecParser(object):
42 42
             while i < totalLines:
43 43
                 line = lines[i].strip()
44 44
                 if self._isConditionalArch(line):
45
-                    if platform.machine() != self._readConditionalArch(line):
45
+                    if self.arch != self._readConditionalArch(line):
46 46
                         # skip conditional body
47 47
                         deep = 1
48 48
                         while i < totalLines and deep != 0:
... ...
@@ -74,7 +75,7 @@ class SpecParser(object):
74 74
                     if not returnVal:
75 75
                         return False
76 76
                     if line.startswith('%package'):
77
-                        pkg = Package(defaultpkg)
77
+                        pkg = Package(self.arch, defaultpkg)
78 78
                         pkg.name = packageName
79 79
                         currentPkg = packageName
80 80
                         self.packages[pkg.name] = pkg
... ...
@@ -94,6 +95,8 @@ class SpecParser(object):
94 94
                     self._readChecksum(line, self.packages[currentPkg])
95 95
                 elif self._isExtraBuildRequires(line):
96 96
                     self._readExtraBuildRequires(line, self.packages[currentPkg])
97
+                elif self._isBuildRequiresNative(line):
98
+                    self._readBuildRequiresNative(line, self.packages[currentPkg])
97 99
                 elif self._isDefinition(line):
98 100
                     self._readDefinition(line)
99 101
                 elif self._isConditionalCheckMacro(line):
... ...
@@ -272,6 +275,11 @@ class SpecParser(object):
272 272
             return True
273 273
         return False
274 274
 
275
+    def _isBuildRequiresNative(self, line):
276
+        if re.search('^%define *buildrequiresnative', line, flags=re.IGNORECASE):
277
+            return True
278
+        return False
279
+
275 280
     def _isChecksum(self, line):
276 281
         if re.search('^%define *sha1', line, flags=re.IGNORECASE):
277 282
             return True
... ...
@@ -439,6 +447,18 @@ class SpecParser(object):
439 439
         pkg.extrabuildrequires.extend(dpkg)
440 440
         return True
441 441
 
442
+    def _readBuildRequiresNative(self, line, pkg):
443
+        data = line.strip()
444
+        words = data.split(" ", 2)
445
+        if len(words) != 3:
446
+            print("Error: Unable to parse line: " + line)
447
+            return False
448
+        dpkg = self._readDependentPackageData(words[2])
449
+        if dpkg is None:
450
+            return False
451
+        pkg.buildrequiresnative.extend(dpkg)
452
+        return True
453
+
442 454
     def _readChecksum(self, line, pkg):
443 455
         strUtils = StringUtils()
444 456
         line = self._replaceMacros(line)
... ...
@@ -532,6 +552,12 @@ class SpecParser(object):
532 532
             dependentPackages.extend(pkg.extrabuildrequires)
533 533
         return dependentPackages
534 534
 
535
+    def _getBuildRequiresNative(self):
536
+        dependentPackages = []
537
+        for pkg in self.packages.values():
538
+            dependentPackages.extend(pkg.buildrequiresnative)
539
+        return dependentPackages
540
+
535 541
     def _getPackageNames(self):
536 542
         packageNames = []
537 543
         for pkg in self.packages.values():
... ...
@@ -589,6 +615,7 @@ class SpecParser(object):
589 589
         specObj.installRequires = self._getRequiresTypeAllPackages("install")
590 590
         specObj.checkBuildRequires = self._getCheckBuildRequiresAllPackages()
591 591
         specObj.extraBuildRequires = self._getExtraBuildRequires()
592
+        specObj.buildRequiresNative = self._getBuildRequiresNative()
592 593
         specObj.listPackages = self._getPackageNames()
593 594
         specObj.listSources = self._getSourceNames()
594 595
         specObj.listPatches = self._getPatchNames()
... ...
@@ -1,4 +1,3 @@
1
-import platform
2 1
 
3 2
 class dependentPackageData(object):
4 3
 
... ...
@@ -8,14 +7,14 @@ class dependentPackageData(object):
8 8
         self.compare = ""
9 9
 
10 10
 class Package(object):
11
-    def __init__(self, basePkg=None):
11
+    def __init__(self, buildarch, basePkg=None):
12 12
         self.summary = ""
13 13
         self.name = ""
14 14
         self.group = ""
15 15
         self.license = ""
16 16
         self.version = ""
17 17
         self.release = ""
18
-        self.buildarch = platform.machine()
18
+        self.buildarch = buildarch
19 19
         self.distribution = "Photon"
20 20
         self.basePkgName = ""
21 21
         self.URL = ""
... ...
@@ -27,6 +26,7 @@ class Package(object):
27 27
         self.buildprovides = []
28 28
         self.checkbuildrequires = []
29 29
         self.extrabuildrequires = []
30
+        self.buildrequiresnative = []
30 31
 
31 32
         self.requires = []
32 33
         self.provides = []
... ...
@@ -70,11 +70,12 @@ class SpecObject(object):
70 70
         # list of subpackage names that have %files section
71 71
         self.listRPMPackages = []
72 72
 
73
-        # Next four lists store dependentPackageData objects
73
+        # Next five lists store dependentPackageData objects
74 74
         self.buildRequires = []
75 75
         self.installRequires = []
76 76
         self.checkBuildRequires = []
77 77
         self.extraBuildRequires = []
78
+        self.buildRequiresNative = []
78 79
         # map subpackage name to list of install requires
79 80
         # dependentPackageData objects
80 81
         self.installRequiresPackages = {}
... ...
@@ -1,5 +1,4 @@
1 1
 import os.path
2
-import platform
3 2
 import traceback
4 3
 import re
5 4
 from CommandUtils import CommandUtils
... ...
@@ -44,7 +43,7 @@ class ToolChainUtils(object):
44 44
             return None
45 45
 
46 46
     def buildCoreToolChainPackages(self):
47
-        self.logger.info("Step 1 : Building the core toolchain packages.....")
47
+        self.logger.info("Step 1 : Building the core toolchain packages for " + constants.currentArch)
48 48
         self.logger.info(constants.listCoreToolChainPackages)
49 49
         self.logger.info("")
50 50
         chroot = None
... ...
@@ -70,7 +69,7 @@ class ToolChainUtils(object):
70 70
             for package in coreToolChainYetToBuild:
71 71
                 self.logger.debug("Building core toolchain package : " + package)
72 72
                 version = SPECS.getData().getHighestVersion(package)
73
-                destLogPath = constants.logPath + "/" + package + "-" + version
73
+                destLogPath = constants.logPath + "/" + package + "-" + version + "." + constants.currentArch
74 74
                 if not os.path.isdir(destLogPath):
75 75
                     CommandUtils.runCommandInShell("mkdir -p " + destLogPath)
76 76
                 chroot = Chroot(self.logger)
... ...
@@ -91,8 +90,8 @@ class ToolChainUtils(object):
91 91
         return pkgCount
92 92
 
93 93
     def getListDependentPackages(self, package, version):
94
-        listBuildRequiresPkg=SPECS.getData().getBuildRequiresForPackage(package, version)
95
-        listBuildRequiresPkg.extend(SPECS.getData().getCheckBuildRequiresForPackage(package, version))
94
+        listBuildRequiresPkg=SPECS.getData(constants.buildArch).getBuildRequiresForPackage(package, version)
95
+        listBuildRequiresPkg.extend(SPECS.getData(constants.buildArch).getCheckBuildRequiresForPackage(package, version))
96 96
         return listBuildRequiresPkg
97 97
 
98 98
     def installToolchainRPMS(self, chroot, packageName=None, packageVersion=None, usePublishedRPMS=True, availablePackages=None):
... ...
@@ -100,9 +99,17 @@ class ToolChainUtils(object):
100 100
         rpmFiles = ""
101 101
         packages = ""
102 102
         listBuildRequiresPackages = []
103
+
104
+        listRPMsToInstall=list(constants.listToolChainRPMsToInstall)
105
+        if constants.crossCompiling:
106
+            targetPackageName = packageName
107
+            packageName = None
108
+            packageVersion = None
109
+            listRPMsToInstall.extend(['binutils-'+constants.targetArch+'-linux-gnu',
110
+                                      'gcc-'+constants.targetArch+'-linux-gnu'])
103 111
         if packageName:
104 112
             listBuildRequiresPackages = self.getListDependentPackages(packageName, packageVersion)
105
-        for package in constants.listToolChainRPMsToInstall:
113
+        for package in listRPMsToInstall:
106 114
             pkgUtils = PackageUtils(self.logName, self.logPath)
107 115
             rpmFile = None
108 116
             version = None
... ...
@@ -113,11 +120,12 @@ class ToolChainUtils(object):
113 113
                 if depPkgName == package:
114 114
                         version=depPkgVersion
115 115
                         break
116
+
116 117
             if not version:
117
-                version = SPECS.getData().getHighestVersion(package)
118
+                version = SPECS.getData(constants.buildArch).getHighestVersion(package)
118 119
 
119 120
             if availablePackages is not None:
120
-                basePkg = SPECS.getData().getSpecName(package)+"-"+version
121
+                basePkg = SPECS.getData(constants.buildArch).getSpecName(package)+"-"+version
121 122
                 isAvailable = basePkg in availablePackages
122 123
             else:
123 124
                 # if availablePackages is not provided (rear case) it is safe
... ...
@@ -125,7 +133,7 @@ class ToolChainUtils(object):
125 125
                 isAvailable = True
126 126
 
127 127
             if constants.rpmCheck:
128
-                rpmFile = pkgUtils.findRPMFile(package, version)
128
+                rpmFile = pkgUtils.findRPMFile(package, version, constants.buildArch)
129 129
 
130 130
             if rpmFile is None:
131 131
                 # Honor the toolchain list order.
... ...
@@ -134,19 +142,21 @@ class ToolChainUtils(object):
134 134
                 # building ('packageName'), then we _must_ use published
135 135
                 # `package` rpm.
136 136
                 if (packageName and
137
-                    packageName in constants.listToolChainRPMsToInstall and
138
-                    constants.listToolChainRPMsToInstall.index(packageName) <
139
-                        constants.listToolChainRPMsToInstall.index(package)):
137
+                    packageName in listRPMsToInstall and
138
+                    listRPMsToInstall.index(packageName) <
139
+                        listRPMsToInstall.index(package)):
140 140
                     isAvailable = False
141 141
                 if isAvailable:
142
-                    rpmFile = pkgUtils.findRPMFile(package, version)
142
+                    rpmFile = pkgUtils.findRPMFile(package, version, constants.buildArch)
143 143
 
144 144
             if rpmFile is None:
145
-                if not usePublishedRPMS or isAvailable:
146
-                    raise Exception("%s-%s not found in available packages" % (package, version))
145
+                if not usePublishedRPMS or isAvailable or constants.crossCompiling:
146
+                    raise Exception("%s-%s.%s not found in available packages" % (package, version, constants.buildArch))
147
+
148
+                # Safe to use published RPM
147 149
 
148 150
                 # sqlite-autoconf package was renamed, but it still published as sqlite-autoconf
149
-                if (package == "sqlite") and (platform.machine() == "x86_64"):
151
+                if (package == "sqlite") and (constants.buildArch == "x86_64"):
150 152
                     package = "sqlite-autoconf"
151 153
                 rpmFile = self._findPublishedRPM(package, constants.prevPublishRPMRepo)
152 154
                 if rpmFile is None:
... ...
@@ -159,6 +169,7 @@ class ToolChainUtils(object):
159 159
             rpmFiles += " " + rpmFile
160 160
             packages += " " + package+"-"+version
161 161
 
162
+        self.logger.debug(rpmFiles)
162 163
         self.logger.debug(packages)
163 164
         cmd = (self.rpmCommand + " -i -v --nodeps --noorder --force --root " +
164 165
                chroot.getID() +" --define \'_dbpath /var/lib/rpm\' "+ rpmFiles)
... ...
@@ -168,14 +179,18 @@ class ToolChainUtils(object):
168 168
             self.logger.error("Installing toolchain RPMS failed")
169 169
             raise Exception("RPM installation failed")
170 170
         self.logger.debug("Successfully installed default toolchain RPMS in Chroot:" + chroot.getID())
171
+
171 172
         if packageName:
172 173
             self.installExtraToolchainRPMS(chroot, packageName, packageVersion)
173 174
 
175
+        if constants.crossCompiling:
176
+            self.installTargetToolchain(chroot, targetPackageName)
177
+
174 178
     def installExtraToolchainRPMS(self, sandbox, packageName, packageVersion):
175
-        listOfToolChainPkgs = SPECS.getData().getExtraBuildRequiresForPackage(packageName, packageVersion)
179
+        listOfToolChainPkgs = SPECS.getData(constants.buildArch).getExtraBuildRequiresForPackage(packageName, packageVersion)
176 180
         if not listOfToolChainPkgs:
177 181
             return
178
-        self.logger.debug("Installing package specific toolchain RPMS for " + packageName +
182
+        self.logger.debug("Installing package specific toolchain RPMs for " + packageName +
179 183
                          ": " + str(listOfToolChainPkgs))
180 184
         rpmFiles = ""
181 185
         packages = ""
... ...
@@ -202,3 +217,39 @@ class ToolChainUtils(object):
202 202
             self.logger.debug("Command Executed:" + cmd)
203 203
             self.logger.error("Installing custom toolchains failed")
204 204
             raise Exception("RPM installation failed")
205
+
206
+    # Install target's core toolchain packages up to 'stopAtPackage' package
207
+    def installTargetToolchain(self, chroot, stopAtPackage=None):
208
+        self.logger.debug("Installing target toolchain RPMS.......")
209
+        pkgUtils = PackageUtils(self.logName, self.logPath)
210
+        rpmFiles = ""
211
+        packages = ""
212
+        for package in constants.listCoreToolChainPackages:
213
+            if stopAtPackage and package == stopAtPackage:
214
+                break
215
+            version = SPECS.getData().getHighestVersion(package)
216
+            basePkg = SPECS.getData().getSpecName(package)
217
+            # install all subpackages of given package
218
+            # for instance: for 'glibc' we want glibc-devel, glibc-tools,
219
+            #               glibc-i18n, etc also to be installed
220
+            subpackages = SPECS.getData().getRPMPackages(basePkg, version)
221
+            for p in subpackages:
222
+                rpmFile = pkgUtils.findRPMFile(p, version, constants.targetArch)
223
+                rpmFiles += " " + rpmFile
224
+                packages += " " + package+"-"+version
225
+
226
+        self.logger.debug(packages)
227
+
228
+        cmd = "mkdir -p " + chroot.getID() +"/target-"+ constants.targetArch+"/var/lib/rpm"
229
+        CommandUtils.runCommandInShell(cmd, logfn=self.logger.debug)
230
+
231
+        if rpmFiles != "":
232
+            cmd = (self.rpmCommand+" -Uvh --nodeps --ignorearch --noscripts --root "+
233
+                   chroot.getID() +"/target-"+ constants.targetArch+
234
+                   " --define \'_dbpath /var/lib/rpm\' "+rpmFiles)
235
+            retVal = CommandUtils.runCommandInShell(cmd, logfn=self.logger.debug)
236
+            if retVal != 0:
237
+                self.logger.debug("Command Executed:" + cmd)
238
+                self.logger.error("Installing toolchain failed")
239
+                raise Exception("RPM installation failed")
240
+        self.logger.debug("Successfully installed target toolchain RPMS in chroot:" + chroot.getID())
... ...
@@ -2,7 +2,6 @@
2 2
 
3 3
 from argparse import ArgumentParser
4 4
 import os.path
5
-import platform
6 5
 import collections
7 6
 import traceback
8 7
 import sys
... ...
@@ -57,6 +56,7 @@ def main():
57 57
                         default="../../common/data/packageWeights.json")
58 58
     parser.add_argument("-bt", "--build-type", dest="pkgBuildType", choices=['chroot', 'container'], default="chroot")
59 59
     parser.add_argument("-F", "--kat-build", dest="katBuild", default=None)
60
+    parser.add_argument("-ct", "--cross-target", dest="targetArch", choices=['x86_64', 'aarch64'], default=None)
60 61
     parser.add_argument("-pj", "--packages-json-input", dest="pkgJsonInput", default=None)
61 62
     parser.add_argument("PackageName", nargs='?')
62 63
     options = parser.parse_args()
... ...
@@ -80,12 +80,12 @@ def main():
80 80
     if not os.path.isdir(options.publishXRPMSPath):
81 81
         logger.error("Given X RPMS Path is not a directory:" + options.publishXRPMSPath)
82 82
         errorFlag = True
83
-    if not os.path.isdir(options.publishRPMSPath + "/" + platform.machine()):
84
-        logger.error("Given RPMS Path is missing " + platform.machine()+
83
+    if not os.path.isdir(options.publishRPMSPath + "/" + constants.buildArch):
84
+        logger.error("Given RPMS Path is missing " + constants.buildArch +
85 85
                      " sub-directory:"+options.publishRPMSPath)
86 86
         errorFlag = True
87
-    if not os.path.isdir(options.publishXRPMSPath+"/" + platform.machine()):
88
-        logger.error("Given X RPMS Path is missing "+platform.machine()+
87
+    if not os.path.isdir(options.publishXRPMSPath+"/" + constants.buildArch):
88
+        logger.error("Given X RPMS Path is missing "+ constants.buildArch +
89 89
                      " sub-directory:"+options.publishXRPMSPath)
90 90
         errorFlag = True
91 91
     if not os.path.isdir(options.publishRPMSPath+"/noarch"):
... ...
@@ -121,8 +121,14 @@ def main():
121 121
         logger.error("Found some errors. Please fix input options and re-run it.")
122 122
         return False
123 123
 
124
-    cmdUtils.runCommandInShell("mkdir -p "+options.rpmPath+"/"+platform.machine())
124
+    if options.targetArch:
125
+        constants.targetArch = options.targetArch
126
+
127
+    cmdUtils.runCommandInShell("mkdir -p "+options.rpmPath+"/"+constants.buildArch)
125 128
     cmdUtils.runCommandInShell("mkdir -p "+options.rpmPath+"/noarch")
129
+    if constants.buildArch != constants.targetArch:
130
+        cmdUtils.runCommandInShell("mkdir -p "+options.rpmPath+"/"+constants.targetArch)
131
+
126 132
 
127 133
     if not os.path.isdir(options.sourceRpmPath):
128 134
         cmdUtils.runCommandInShell("mkdir -p "+options.sourceRpmPath)
... ...
@@ -176,14 +182,25 @@ def main():
176 176
         elif options.toolChainStage == "stage2":
177 177
             pkgManager = PackageManager()
178 178
             pkgManager.buildToolChainPackages(options.buildThreads)
179
-        elif options.installPackage:
180
-            buildSpecifiedPackages([package], options.buildThreads, options.pkgBuildType)
181
-        elif options.pkgJsonInput:
182
-            buildPackagesInJson(options.pkgJsonInput, options.buildThreads,
183
-                                options.pkgBuildType, pkgInfoJsonFile, logger)
184 179
         else:
185
-            buildPackagesForAllSpecs(options.buildThreads, options.pkgBuildType,
186
-                                     pkgInfoJsonFile, logger)
180
+            if constants.buildArch != constants.targetArch:
181
+                # It is cross compilation.
182
+                # first build all native packages
183
+                buildPackagesForAllSpecs(options.buildThreads,
184
+                                         options.pkgBuildType,
185
+                                         pkgInfoJsonFile, logger)
186
+                # Then do the build to the target
187
+                constants.currentArch = constants.targetArch
188
+                constants.crossCompiling = True
189
+
190
+            if options.installPackage:
191
+                buildSpecifiedPackages([package], options.buildThreads, options.pkgBuildType)
192
+            elif options.pkgJsonInput:
193
+                buildPackagesInJson(options.pkgJsonInput, options.buildThreads,
194
+                                    options.pkgBuildType, pkgInfoJsonFile, logger)
195
+            else:
196
+                buildPackagesForAllSpecs(options.buildThreads, options.pkgBuildType,
197
+                                         pkgInfoJsonFile, logger)
187 198
     except Exception as e:
188 199
         logger.error("Caught an exception")
189 200
         logger.error(str(e))
... ...
@@ -1,3 +1,4 @@
1
+import platform
1 2
 from Logger import Logger
2 3
 
3 4
 class constants(object):
... ...
@@ -30,6 +31,10 @@ class constants(object):
30 30
     buildOptions = {}
31 31
     # will be extended later from listMakeCheckRPMPkgtoInstall
32 32
     listMakeCheckRPMPkgWithVersionstoInstall = None
33
+    buildArch = platform.machine()
34
+    targetArch = platform.machine()
35
+    crossCompiling = False
36
+    currentArch = buildArch
33 37
 
34 38
     noDepsPackageList = [
35 39
         "texinfo",