1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Newbie Question: Compiling a simple Helloworld.c program

Discussion in 'Tomato Firmware' started by cog_7, Nov 19, 2012.

  1. cog_7

    cog_7 Serious Server Member

    Hi:

    I am struggling immensely with trying to figure out how to compile a 'helloworld.c' program that I can run on my ASUS-RT-N16 router. If anyone can help me, I would be very grateful.

    Note:
    (i) The firmware on my router is: Shibby (TomatoUSB mod)
    (ii) I can compile the firmware 'tomatousb-K26-1.28.9054.beta' using this procedure: How to build, and rebuild Tomato, FOR TOTAL NOOBS: (http://tomatousb.org/tut:how-to-build-and-rebuild-tomato-for-total-noobs) without a problem.
    (iii) I don't know if this article would be of any help: http://www.linksysinfo.org/index.ph...ompiling-small-application.25905/#post-121462. My problem is dealing with the MakeFiles in here - to just compile one script.

    Here is my 'helloworld.c' souce code:
    /****************
    * Helloworld.c
    *****************/
    #include <stdio.h>

    int main(void)
    {
    printf("Hell! O' world, why won't my code compile?\n\n");
    return 0;
    }

    Here is my 'MakeFile':
    # build helloworld executable when user executes "make"
    helloworld: helloworld.o
    $(CC) $(LDFLAGS) helloworld.o -o helloworld
    helloworld.o: helloworld.c
    $(CC) $(CFLAGS) -c helloworld.c

    # remove object files and executable when user executes "make clean"
    clean:
    rm *.o helloworld

    The above compiled and ran on my ubuntu 12.10 64bit box.

    Thanks.
     
  2. koitsu

    koitsu Network Guru Member

    Your problem pertains to cross-architecture building. You need a build toolchain so that you can build MIPSR1/R2 binaries on a x86/x64 PC (your Ubuntu box). Once you have the toolchain built, you need to adjust your Makefile to set CC and LDFLAGS, and possibly others, to point to x86/x64 gcc binary that builds MIPS binaries, and links against uClibc (vs. the Ubuntu system libc), respectively. You can get an idea for the arguments/etc. from building the firmware yourself and peeking around. I would recommend doing this atop your Makefile:

    Code:
    CC=/opt/brcm/hndtools-mipsel-linux/bin/gcc
    
    You also need to define LDFLAGS to something, and I can't help give you that without examining the output from a full toolchain build. It will certainly contain lots of -L flags, since you'll be linking against uClibc and not your system's libc. There may also be CFLAGS adjustments for architectural differences or optimisations (I imagine bare minimum some -I flags as well).

    The 2nd URL you listed told you what to go look at src/router/httpd/Makefile and bits for an example of what to put in your own Makefile. So have you done that? If not, why not?

    Some general comments in passing:

    1. Your hello world program's main() should not be void -- main on *IX always provides argc and argv, even if you don't need them. Change the declaration to this and get in the habit of always doing this:

    Code:
    int main(int argc, char *argv[])
    
    2. I advise learning GNU make syntax. I'm not as familiar with GNU make as I am with BSD make, but you could re-write the above into something that scales better:

    Code:
    OBJS=helloworld.o
     
    all: helloworld
     
    helloworld: ${OBJS}
        ${CC} ${CFLAGS} -o ${.TARGET} ${.ALLSRC}
     
    ${OBJS}: yourlocalincludefiles.h
        ${CC} ${CFLAGS} -c ${.PREFIX}.c
     
    clean:
        rm -f helloworld *.o *.core
    
    Since your helloworld program doesn't use any local include files (i.e. #include "myinclude.h"), you can just set that line to be ${OBJS}: and that should do it.

    Sorry I can't input literal tabs in front of the commands that have 4 spaces or so. They should be tabs and not spaces (GNU make lets you get away with using spaces, but other makes do not).

    Make more sense?
     
  3. JugsteR

    JugsteR Serious Server Member

    I must say, Koitsu, I am impressed both with your knowledge and the amount of time you must put in each very detailed answer. Kudos to you!

    Signature? Signature!
     
  4. cog_7

    cog_7 Serious Server Member

    Thanks Koitsu for the in depth response.

    (i) I am going to take your advice an research the GNU make syntax.
    (ii) What toolchain would you (or anyone else) recommend me to use? The router I have is an ASUS RT-N16, and I am using the Shibby firmware and Entware or Optware.

    Regards
    COG
     
  5. koitsu

    koitsu Network Guru Member

    The term "toolchain" refers to compiling a bunch of tools that can then compile binaries for the CPU architecture you're trying to write utilities on. Meaning, a toolchain consists of things like gcc, g++, ld, ar, etc. that will build MIPS (R1 or R2) binaries for you, yet can run on x86/x64 architecture. These allow for an x86/x64 system to build MIPSR1/R2 binaries for use on an Asus RT-N16 router, for example. The file command might interest you too.

    So when you ask me "what toolchain should I use?", the question itself means you didn't know what the term toolchain meant. Now you do. :)

    The toolchain is then used to build libraries that underlying programs (like the one you're building) will rely on. The most important two are the ld.so ELF loader, and libc. On Tomato/TomatoUSB firmwares, however, standard GNU libc isn't used (it's too bloated/large) -- an alternate libc library called uClibc is used. So when you generate a binary (such as helloworld, which obviously relies on libc), you need to make sure it links against uClibc and not libc.

    To see one in action, go build a TomatoUSB firmware (Shibby, Toastman, etc.), then look in that /opt/brcm/hndtools-mipsel-linux/bin directory I gave you above. You'll find utilities in there which are the same as ones you'd find on your local system, except they're used for building/linking/etc. MIPS binaries, not x86/x64 binaries.
     

Share This Page