Compile Programs

From Omnifi Wiki

Jump to: navigation, search
Quick Links
Related topics
  • Find Something
    • To Put Here

edit

Contents

[edit] So You Want To Compile Programs For The DMP1?

This is a relatively easy task - provided you understand the limitations of what you can and cannot do. However, because I am not an expert in these things, much of what you see below may be simplistic. Those who feel saavy, please feel free to extend this tutorial. I only ask that you do not write it from a "you-should-be-able-to-do-this" context. Instead, show all work so that it's reproducible by another, uninformed individual.

[edit] Get A Cross Compiler

This is perhaps the biggest "gotcha." You can't use your Microsoft Visual C or your .NET C# compiler--they only produce binaries that run on Windows platforms (mostly). You must get a compiler that produces a binary that runs on the ARM Microprocessor architechture.

Fortunately, there is already a tutorial on how to do that, available from here. A cross compiler is a specialized compiler that runs on one platform, but generates code for another. That is, you can build a cross compiler that runs on your Windows Machine (via Cygwin) but creates an executable that runs on the DMP1 (or any other ARM microprocessor device). Or you can build Windows executables from your Linux machine--whatever.

[edit] Why Can't We Just Build A Compiler On The DMP1?

That's a good question. This would be known as a native compiler and is probably the best way to compile programs. But there's a small problem - the DMP1 (and DMS1) is not a development environment. The linux OS doesn't have the compiler built-into it. It doesn't even have an assembler and linker (which would be needed as well). Worse yet, even if we did have a compiler that runs on the DMP1 it probably would be woefully slow.

[edit] Setting Up To Compile

This is a tricky topic and there are several options. Each has its merits, but I will illustrate only one below and it seems to work reasonably well.

[edit] Build Multiple Cross Compilers

If you're only interested in compiling openfi and nothing else, then all you probably need is the crosstools compiler. It's stable, industrial-strength and produces an output that the DMP1 and DMS1 can execute well. It is used to build openfi. However, if you're interested in compiling other programs, you'd want to explore compiling with the buildroot compiler. That's because currently (as of Feb 2006), we have not produced a replacement kernel for the DMP1. As a result, the we cannot dynamically link to libraries used on the DMP1 because we do not know the options that was used in the compile--we must build everything as a static compile.

Statically compiled code includes a copy of the library included with the executable--it should not have to rely on the OS / kernel for that code. As a result, even a small piece of code such as a one-line printf("Hello World\n"); program will be tens of thousands of bytes because all of the libraries necessary to open files and write to stdout must be built into executable as well.

Crosstool is great, but it does have limitations. Certain library functions, such as getHostByName() cannot be statically linked using crosstool, and thus progams that rely on this function will fail when run on the DMP1. Some programs built by crosstools will not be recognized by the DMP1 as an executable file at all!!!

Where crosstool fails, builtroot does well! That particular getHostByName() function can be statically linked, along with just about anything else. It also has an added benefit that it produces a much, much smaller binary output than crosstool does. For example, a 800 KB rsync built with crosstools can be recompiled by builtroot and be only 344 KB!

But there's another caveat: sometimes the binary that buildroot creates will not run properly on the DMP1. For example, buildroot will compile openfi but openfi will not run properly on the DMP1 -- it'll load up and control the display on the LCD, but any attempts to play a song will fail.

So, it's a good idea to have two crosscompilers around. The tutorial will show how to build both of them. Build a program with each one of them, and see which one works. Generally, I prefer programs built with buildroot (smaller), but am leery about certain functions in which case I'll resort to crosstools.

[edit] Setting Up Your Environment

For the purposes of this exercise, I'm going to assume you're running on a Linux box and it has its own native compiler (one that produces an output that runs on the Linux box), and that you've built a cross compiler (or two) and have that sitting in some arbitrary directory.

Most programs use the gcc (GNU Compiler Collection) compiler. To see which default compiler will be invoked, you can type the following from your shell:

~# which gcc
/usr/bin/gcc
~# _

On my Linux box, this is the native compiler that came with my Linux install. If I build programs using this compiler, I'd build it to run on my Linux box and that's not what I want to do.

The trick is to "train" the OS to use the cross compiler instead of the native compiler. This is best done through the use of the system path.

~# echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/opt/bin:/usr/local/games:
/opt/jdk1.5.0_06//bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/xfce4/bin:
/usr/X11R6/bin:/opt/xfce4/bin
~# export PATH=/root/buildroot/build_arm_nofpu/staging_dir/arm-linux-uclibc/bin/:$PATH
~# which gcc
/root/buildroot/build_arm_nofpu/staging_dir/arm-linux-uclibc/bin/gcc
~# _

I've now inserted the path to the buildroot compiler in front of the original PATH string, and the OS finds it first so it'll use that instead. Alternately, I could have done the following to use the crosstools compiler instead:

~# export PATH=/opt/crosstool/gcc-3.4.1-glibc-2.3.3/arm-softfloat-linux-gnu/arm-softfloat-linux-gnu/bin/:$PATH
~# which gcc
/opt/crosstool/gcc-3.4.1-glibc-2.3.3/arm-softfloat-linux-gnu/arm-softfloat-linux-gnu/bin/gcc
~# _

The section in red above is dependent upon your particular installation, of course. Additionally, I've created symbolic links to my buildroot in a different directory so I just type the following:

~# export PATH=/opt/arm-uclibc/:$PATH
~# which gcc
/opt/arm-uclibc/gcc
~# _

Another thing you'll want to keep in mind are compiler and linker flags. Code for the DMP1 must be linked statically, and it's best to turn on the flags that will optimize for size. Type the following:

~# export CFLAGS="-Os -Wall -static"
~# export LDFLAGS="-static"
~# _

Sometimes you'd feel inclined to do the following, but it's not necessary at all (especially after exporting the PATH):

~# export CC=/root/buildroot/build_arm_nofpu/staging_dir/arm-linux-uclibc/bin/

Now, you're basically set up!

[edit] Build The Project

Many progams you download will come to you as a tar.gz file which you must unpack and lay out. Often times, you'll perform a configure followed by a make. Consider the following series of statements taken from this page. It illustrates the steps needed to download the source from a website, unpack it, set the PATH and environment variables and begin the build:

~# wget http://matt.ucc.asn.au/dropbear/dropbear-0.47.tar.bz2
07:54:23 (168.77 KB/s) - `dropbear-0.47.tar.bz2' saved [1418374/1418374
~# tar xf dropbear-0.47.tar.bz2 
~# cd dropbear-0.47/
~/dropbear-0.47# export PATH=/opt/arm-uclibc:${PATH}
~/dropbear-0.47# export CFLAGS="-Os -static -Wall"
~/dropbear-0.47# export LDFLAGS="-static"
~/dropbear-0.47# ./configure --host=arm --build=i386-linux --disable-zlib
(blah, blah, blah ...)
~/dropbear-0.47# make PROGRAMS=dropbear strip
(compile, compile, compile ...)
~/dropbear-0.47# make strip
(blah, blah, blah ...)
~/dropbear-0.47# _

You will see that I've passed the --host=arm --build=i386-linux flags to configure. We're telling configure that we're going to do a cross-compile for the ARM. Configure will then create a Makefile that has all of the necessary flags to compile. Additionally, it tells configure not to test the output of some programs that are compiled by this compiler because it will not run on that box.

[edit] Some Screwy Builds

On some compiles, the Makefile wants to compile something with the native compiler so that it can perform an intermediary step on the native machine before it is compiled into the cross-compiled program. The particular usage may differ for each project and each configure script, but you may be able to provide an additional flag for this purpose. Consider the following, taken from this page:

~# wget ftp://ftp.gnu.org/non-gnu/flex/flex-2.5.4a.tar.gz
23:57:23 (264.88 KB/s) - `flex-2.5.4a.tar.gz' saved [380995]
~# tar xf flex-2.5.4a.tar.gz
~# cd flex-2.5.4/
~/flex-2.5.4# export PATH=/opt/arm-uclibc/:${PATH}
~/flex-2.5.4# export CFLAGS="-Os -static -Wall"
~/flex-2.5.4# export LDFLAGS="-static"
~/flex-2.5.4# ./configure --host=arm
              --build=i386-linux --without-cxx --with-build-cc=/usr/bin/gcc
              --exec-prefix=/root/projects/buildroot/build_arm_nofpu/staging_dir/
              --prefix=/root/projects/buildroot/build_arm_nofpu/staging_dir/
(blah, blah, blah ...)
~/flex-2.5.4# make
(compile, compile, compile ...)
~/flex-2.5.4# make install
(blah, blah, blah ...)
~/flex-2.5.4# _

The configure script knows that it's going have to do an intermediary compile that requires the use of the native compiler. The programmer graciously provided us with the option --with-build-cc to enable us to specify our native compiler for this purpose.

[edit] Building A Library

With some projects, you'll get halfway through the configure and it'll error out telling you that you're missing a library (like ncurses, or flex). You'll have to back up and download, compile and install that first. Again, the example above shows the step where we download flex-2.5.4 and build it. We provided the path to the exec dirs where the libraries and executables will be stored with --exec-prefix and --prefix statements. Then we did a make install to have the Makefile actually put the files out there.

Then the next part of compiling the main project would find those files and be able to configure without errors and be able to compile normally.

[edit] Some Projects Are Even Simpler

They may not have a configure step. Openfi is such a project -- it just comes with a Makefile and you simply invoke it using make.

Others have a Makefile that you have to edit and point the various flags to the appropriate cross-compiler. The mini-httpd project is such a monster. You may also have to provide the "-Os -Wall -static" flags directly in the edited Makefile as well.

[edit] Making An Even Smaller Output

After some compiles, you'll have an executable that'll work. But often, they'll contain symbol tables that are used in debugging but not needed in a Production environment. You can run the strip command (there's one that comes with crosstools, and one that comes with buildroot) which will strip this information off and produce a smaller package.

~# which strip
/opt/arm-uclibc/strip
~# strip openfi
~# _

Some Makefiles have a strip step, or a strip option. Again, you'll have to inspect each Makefile or read the README file carefully for what you can and cannot do.

[edit] Put It Onto The DMP1 And Run It

[edit] Method One

You can plug the DMP1 HDD into your PC and mount it:

~# mkdir /omnifi
~# mount -t vfat  /dev/sda1  /omnifi
~# cd /omnfi
~# _

Then you can create a directory on here, such as mydir and copy your files into it.

~# pwd
/omnfi/
~# mkdir  mydir
~# cp  ~/myproj/*  /omnifi/mydir/
~# _

When you plug your HDD back into the DMP1, you'll find it in:

/storage/disc1/mydir/

And you should be able to invoke the program normally from this directory when you rlogin to the DMP1.

[edit] Method Two

You can FTP the files onto your DMP1 wirelessly:

Rlogin to the DMP1 and navigate to:

# cd /storage/disc1/
# discWE
# mkdir  mydir
# _

Then from your Linux box, do the following:

~# ftp dmp1
Connected to 192.168.1.15.
220 Please enter your name:
Name (192.168.1.15:root): root
331 User name okay, Need password.
Password:
230 User logged in.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> 
ftp> lcd ~/myproj/
Local directory now ~/myproj/
ftp> cd /storage/disc1/mydir
250 "/storage/disc1/mydir/" is current directory.
ftp> binary
200 Type set to Binary
ftp> prompt
Interactive mode off.
ftp> mput *
(blah, blah, blah)
200 PORT command successful
ftp> bye
221 Goodbye.  Control connection closed.
~# _

Then on your rlogin session don't forget to do the following:

# sync
# discWD
# _

Now you can invoke the program.

# /storage/disc1/mydir/myprog
# _

[edit] Do Some Compiles Of Your Own

Follow the links below where we've described how to compile these programs, step-by-step. Get comfortable with the process, then go find some other programs to compile for yourself.

[edit] Cross Compilers For Other Platforms

An interesting concept that a number of people have gotten working (but not yours truly) is Scratchbox. This is a unique concept where you build a virtual ARM environment on your Linux box. That is, once your install and fire up scratchbox, you'll log into the scratchbox environment, then build and compile ARM programs as if it were a native compiler, and you are able to run your programs in this environment.

If anyone gets this up and running, please help us by documenting it on this wiki.  :D

There are other emulators as well:

[edit] Related Links

[edit] External Links

Lumkichi 10:56, 15 Feb 2006(CST)

I'd like to credit the following people for helping me understand this process well enough to document it:

  • Andy Poling
  • Lincomatic
  • Dan Zenchelsky