Cross Compiling Linux Kernel for TX1

So I’m trying to recompile the linux kernel with a very small modification in order to get the jetson to work with Point Grey Cameras as per these instructions. However these instructions were designed for the TK1, and apparently compiling the kernel natively on the TX1 doesn’t work. I’ve found a couple useful topics on the matter
https://devtalk.nvidia.com/default/topic/901677/building-tx1-kernel-from-source/
https://devtalk.nvidia.com/default/topic/894945/jetson-tx1/jetson-tx1/10
but I’ve never cross compiled anything in my life, so I have no idea what I’m doing. Anyone have instructions to help me out with this? Or at least some resources to get started with cross compiling? I’ using L4T R24.1, and the host machine is 64 bit ubuntu 14.04.

The links you mentioned contain most everything needed to cross-compile a kernel. The most confusing part is a combination of knowing which cross-compiler to install or use, and some of the edits to the R24.1 kernel’s source to get past some initial bugs.

FYI, the information below is more detailed than most will need. Many people will use an Ubuntu host and the compilers are all just a package manager command to get the right one. Myself and others have to download and sometimes compile our own tool chains, which gets a lot more complicated…this is why there is so much extra detail in what follows.

As a highlight to cross-compiling in general, you’ll see the Linaro brand of cross tool chains mentioned a lot, they have very good ARMv7 (32-bit), ARMv8 (32-bit), and ARMv8-a (64-bit) support, and tend to produce fast running code. You will see naming conventions of various compiler releases which tend to abbreviate the 32-bit code to output as “arm”, and the 64-bit code to output as either “arm64” or “aarch64”. Because the compilers run on a desktop Intel/AMD 64-bit host, but produce some ARM variant of output, you will also see naming of the cross tool chains end with x86_64…this is because they run on x86_64 even though they produce code incapable of running on the machine that compiles the code.

In addition to architecture, you will see naming as to the environment the code will run in as well: The o/s the compiled/produced code is to run on is “linux” or “none”, where “none” means there is no operating system…this would include the boot loader (technically the kernel is also “none”, but I’ve always used the “linux” compilers for this). Nothing you work with for kernel or user space will require “none”, everything you work with on Jetson works with “linux”. Ignore “none”.

Related to the operating system naming you may also see naming related to calling convention…if you see “eabihf”, this refers to the operating system using support for hardware floating point (embedded application binary interface, hard float). EABIHF applies to the Jetson TK1 and is used only with 32-bit. Without the “hf” of “eabihf” the compiler floating point hardware would not be used (it’d be software floating point)…older ARMv7 processors optionally may or may not have had floating point hardware. The newer ARMv8-a environments do not differentiate as to hard float or not, they all support hardware floating point. If you see “eabi” without “hf”, don’t use it (all of the 32-bit ARM CPUs from nVidia Tegra have supported hardware floating point for a very long time…there was a time when Tegra 3 had the floating point hardware but still used software floating point…this eventually became hardware floating point and software floating point went away completely in L4T). If there is no mention of either eabihf or eabi while looking at 64-bit tools, you’ve got what you want. If you see eabihf in relation to 32-bit, you’ve got what you want.

Because the Jetson TX1 supports both 32-bit (ARMv8) and 64-bit code (ARMv8-a), kernel cross compile will involve two tool chains instead of one. Thus you will see something like “gcc-linaro-5.2-2015.11-x86_64_aarch64-linux-gnu” and also “gcc-linaro-5.2-2015.11-x86_64_arm-linux-gnueabihf”. Note that both are part of the same release date, but one names “arm/gnueabihf” and one names “aarch64”.

Within the bin directory of native tools which produce code for the same thing that the compiler runs on there is no special prefix to any tool name, e.g., the compiler is just “gcc”. Within the bin directory of cross tool chains there will be a “prefix” which keeps it straight as to what is being output when a host has multiple compilers. For the 64-bit JTX1 cross compile, this prefix will be “aarch64-linux-gnu-”, thus all of the files in the bin directory of this cross tool chain start with that…“gcc” becomes “aarch64-linux-gnu-gcc”. If your tool chain is located at “/usr/local/gcc-linaro-5.2-2015.11-x86_64/bin/”, then “gcc” for that cross tool chain could be called by combining the path “/usr/local/gcc-linaro-5.2-2015.11-x86_64/bin/” with the prefix “aarch64-linux-gnu-”, and the actual compiler “gcc”: “/usr/local/gcc-linaro-5.2-2015.11-x86_64/bin/aarch64-linux-gnu-gcc”. The kernel Makefile (and many software projects) calls the path up to the bin directory plus prefix CROSS_COMPILE, and understands if “gcc” is called to prefix gcc with CROSS_COMPILE to get the right tool chain. If you don’t set CROSS_COMPILE, then just ordinary gcc is used…if CROSS_COMPILE is set, path prefix is automatic.

The Makefile can also change behavior if you have set variable CROSS32CC…this is a specific full path to a 32-bit compiler, not a prefix to an entire chain. If you were to cross-compile a 32-bit kernel you would name the tool chain prefix, not a specific gcc…for a “mostly 64-bit kernel” which is also working with 32-bit, you will see CROSS32CC as the full path to an exact gcc compiler. In my case where I have a 32-bit gcc cross compiler at “/usr/local/gcc-linaro-5.2-2015.11-x86_64_arm-linux-gnueabihf/bin/”, CROSS32CC is set to “/usr/local/gcc-linaro-5.2-2015.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc”.

The way to use those variables is to set them as an environment variable before kernel build. Most people set something as an environment variable so they can avoid typing out long lines at each build step. Those URLs you mentioned above show this in detail. The general rule though is:

export CROSS_COMPILE=...your path...aarch64-linux-gnu-
export CROSS32CC=...your path...arm-linux-gnueabihf-gcc
export ARCH=arm64
...whatever "make" in kernel source now uses those...

There are many Makefiles which take advantage of this scheme, but if not, the details have to be set up manually…kernel source has so much support for this already that if you have tools in place it becomes trivial to cross-compile. You just have to remember to set the environment variables, and you’re ready.

Thanks so much for the detailed help. Your post cleared up a lot of confusing issues. I’m able to get it working now.

I’m necroing this post to say: Thanks for the clear summary of the specifics of the Tegra cross-compilation names-of-things.
Those, plus “locate,” made me a happy man :-)