C and assembly development introduction: Difference between revisions

From Hackspire
Jump to navigation Jump to search
m (Upgrade binutils dependency to 2.23.1.)
(Update install script from https://ndlessly.wordpress.com/2013/06/15/cpp-for-the-ti-nspire/#comments)
Line 16: Line 16:
  # Edited by Travis Wiens ( http://blog.nutaksas.com/2009/05/installing-gnuarm-arm-toolchain-on.html )
  # Edited by Travis Wiens ( http://blog.nutaksas.com/2009/05/installing-gnuarm-arm-toolchain-on.html )
  # Edited by Lionel Debroux for newer gcc/binutils/newlib/gdb versions and nspire-gcc.
  # Edited by Lionel Debroux for newer gcc/binutils/newlib/gdb versions and nspire-gcc.
 
  TARGET=arm-none-eabi
  TARGET=arm-none-eabi
  PREFIX=$HOME
  PREFIX=/usr/local
  PARALLEL="" # or "-j<number of build jobs>"
  PARALLEL="-j2" # or "-j<number of build jobs>"
 
  BINUTILS=binutils-2.23.1 # http://www.gnu.org/software/binutils/
  BINUTILS=binutils-2.23.2 # http://www.gnu.org/software/binutils/
  GCC=gcc-4.6.3 # http://gcc.gnu.org/
  GCC=gcc-4.8.1 # http://gcc.gnu.org/
  NEWLIB=newlib-1.20.0 # http://sourceware.org/newlib/
  NEWLIB=newlib-2.0.0 # http://sourceware.org/newlib/
  GDB=gdb-7.4 # http://www.gnu.org/software/gdb/
  GDB=gdb-7.6 # http://www.gnu.org/software/gdb/
   
 
  mkdir build-binutils
  mkdir build
  mkdir build
 
  # IMPORTANT NOTE: in order to compile GCC 4.5, you need the GMP, MPFR and MPC development libraries.
  # IMPORTANT NOTE: in order to compile GCC 4.8, you need the GMP, MPFR and MPC development libraries.
  # For example, if you have installed them yourself in $PREFIX, you'll have to add --with-gmp=$PREFIX --with-mpfr=$PREFIX --with-mpc=$PREFIX .
  # For example, if you have installed them yourself in $PREFIX, you'll have to add --with-gmp=$PREFIX --with-mpfr=$PREFIX --with-mpc=$PREFIX.
 
  # NOTE: the second rm -rf is commented, because it's not strictly necessary.
  # NOTE: the second rm -rf is commented, because it's not strictly necessary.
 
  # Section 1: binutils.
  # Section 1: GNU Binutils.
  (wget -c http://ftp.gnu.org/gnu/binutils/$BINUTILS.tar.bz2 && tar xvjf $BINUTILS.tar.bz2 && cd build && ../$BINUTILS/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --with-system-zlib --with-gnu-as --with-gnu-ld --disable-nls --with-float=soft --disable-werror && make $PARALLEL all && make install && cd .. && rm -rf build/*) || exit 1;
  (wget -c http://ftp.gnu.org/gnu/binutils/$BINUTILS.tar.bz2 && tar xvjf $BINUTILS.tar.bz2 && cd build-binutils && ../$BINUTILS/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --with-system-zlib --with-gnu-as --with-gnu-ld --disable-nls --with-float=soft --disable-werror && make $PARALLEL all && make install && cd ..) || exit 1;
  ##rm -rf $BINUTILS $BINUTILS.tar.bz2
  ##rm -rf $BINUTILS $BINUTILS.tar.bz2
 
  # Section 2: GCC, step 1.
  # Section 2: GCC, step 1.
  (wget -c ftp://ftp.gnu.org/gnu/gcc/$GCC/$GCC.tar.bz2 && tar xvjf $GCC.tar.bz2 && cd build && ../$GCC/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --enable-languages="c,c++" --with-system-zlib --with-newlib --without-headers --disable-shared --with-gnu-as --with-gnu-ld --with-float=soft --disable-werror && make $PARALLEL all-gcc && make install-gcc && cd .. && rm -rf build/*) || exit 1;
  (wget -c ftp://ftp.gnu.org/gnu/gcc/$GCC/$GCC.tar.bz2 && tar xvjf $GCC.tar.bz2 && cd build && ../$GCC/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --enable-languages="c,c++" --with-system-zlib --with-newlib --without-headers --disable-shared --with-gnu-as --with-gnu-ld --with-float=soft --disable-werror && make $PARALLEL all-gcc && make install-gcc && cd .. && rm -rf build/*) || exit 1;
  ##rm -rf $GCC.tar.bz2
  ##rm -rf $GCC.tar.bz2
 
  # Section 3: newlib.
  # Section 3: Newlib.
  (wget -c ftp://sources.redhat.com/pub/newlib/$NEWLIB.tar.gz && tar xvzf $NEWLIB.tar.gz && cd build && ../$NEWLIB/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --with-gnu-as --with-gnu-ld --disable-nls --with-float=soft --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;
  (wget -c ftp://sourceware.org/pub/newlib/$NEWLIB.tar.gz && tar xvzf $NEWLIB.tar.gz && cd build && ../$NEWLIB/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --with-gnu-as --with-gnu-ld --disable-nls --with-float=soft --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;
  ##rm -rf $NEWLIB $NEWLIB.tar.gz
  ##rm -rf $NEWLIB $NEWLIB.tar.gz
 
  # Section 4: GCC, step 2. Yes, this is necessary.
  # Section 4: GCC, step 2. Yes, this is necessary.
  (cd build && ../$GCC/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --enable-languages="c,c++" --with-system-zlib --with-newlib --disable-shared --with-gnu-as --with-gnu-ld --with-float=soft --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1
  (cd build && ../$GCC/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --enable-languages="c,c++" --with-system-zlib --with-newlib --disable-shared --with-gnu-as --with-gnu-ld --with-float=soft --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1
  ##rm -rf $GCC
  ##rm -rf $GCC
 
  # Section 5: GDB.
  # Section 5: GDB.
  (wget -c ftp://ftp.gnu.org/gnu/gdb/$GDB.tar.bz2 && tar xvjf $GDB.tar.bz2 && cd build && ../$GDB/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;
  (wget -c ftp://ftp.gnu.org/gnu/gdb/$GDB.tar.bz2 && tar xvjf $GDB.tar.bz2 && cd build && ../$GDB/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;
  ##rm -rf $GDB $GDB.tar.bz2
  ##rm -rf $GDB $GDB.tar.bz2
 
# Section 6: elf2flt.
cat > Ndless-elf2flt.patch << EOF
91a92,97
> #define R_ARM_CALL    28
> #define R_ARM_JUMP24  29
> #define R_ARM_TARGET1 38
> #define R_ARM_V4BX    40
> #define R_ARM_TARGET2 41
> #define R_ARM_PREL31  42
647a654,660
>                              case R_ARM_NONE:
>                              case R_ARM_PREL31:
>                              case R_ARM_TARGET1:
>                              case R_ARM_TARGET2:
>                              case R_ARM_CALL:
>                              case R_ARM_V4BX:
>                              case R_ARM_JUMP24:
EOF
 
(cvs -z3 -d:pserver:anonymous@cvs.uclinux.org:/var/cvs checkout -P elf2flt && patch elf2flt/elf2flt.c Ndless-elf2flt.patch && cd build && ../elf2flt/configure --target=$TARGET --prefix=$PREFIX -with-libbfd=../build-binutils/bfd/libbfd.a --with-libiberty=../build-binutils/libiberty/libiberty.a --with-bfd-include-dir=../build-binutils/bfd --with-binutils-include-dir=../$BINUTILS/include && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;


*Create symbolic links to <tt>arm-linux-gnueabi-*</tt> for the different GCC tools (ld, gcc, objcopy, ...) if your installation use custom file names.
*Create symbolic links to <tt>arm-linux-gnueabi-*</tt> for the different GCC tools (ld, gcc, objcopy, ...) if your installation use custom file names.
====Since Ndless SDK r825: elf2flt====
*Install and build elf2flt depedencies, and build elf2flt as described [https://github.com/tangrs/ndless-bflt-toolchain here]. Make sure to use the patched version of elf2flt distributed in ''elf2flt/'' of the Ndless SDK.


===Verifying the installation===
===Verifying the installation===

Revision as of 11:27, 17 June 2013

This tutorial describes how to set up an environment and use the Ndless SDK to write native Ndless-compatible programs for the TI-Nspire on Linux.

If you are looking for a Windows tutorial, get one in the development resources of ndlessly.

Setting up a development environment

  • Get the Ndless SDK which resources for C and assembly development on TI-Nspire. This article is written for the Ndless SDK v3.1 beta r695 and higher.
  • Add the ndless/bin/ directory of the SDK to your PATH environment variable (see this tutorial). If you don't like messing with PATH stuff, it's easy to just link the files inside. As root in the sdk/bin directory, run "link ./nspire-* /bin/nspire-*" where * is replaced with gcc, as and ld.
  • Choose an emulator that will ease the development of programs
  • Install a GNU ARM toolchain. You can use the following script:
    • No need to be root
    • Add $HOME/bin to $PATH
    • You need the GMP, MPFR, MPC and CURSES development libraries.
#!/bin/sh
# Written by Uwe Hermann <uwe@hermann-uwe.de>, released as public domain.
# Edited by Travis Wiens ( http://blog.nutaksas.com/2009/05/installing-gnuarm-arm-toolchain-on.html )
# Edited by Lionel Debroux for newer gcc/binutils/newlib/gdb versions and nspire-gcc.
 
TARGET=arm-none-eabi
PREFIX=/usr/local
PARALLEL="-j2" # or "-j<number of build jobs>"
 
BINUTILS=binutils-2.23.2 # http://www.gnu.org/software/binutils/
GCC=gcc-4.8.1 # http://gcc.gnu.org/
NEWLIB=newlib-2.0.0 # http://sourceware.org/newlib/
GDB=gdb-7.6 # http://www.gnu.org/software/gdb/
 
mkdir build-binutils
mkdir build
 
# IMPORTANT NOTE: in order to compile GCC 4.8, you need the GMP, MPFR and MPC development libraries.
# For example, if you have installed them yourself in $PREFIX, you'll have to add --with-gmp=$PREFIX --with-mpfr=$PREFIX --with-mpc=$PREFIX.
 
# NOTE: the second rm -rf is commented, because it's not strictly necessary.
 
# Section 1: GNU Binutils.
(wget -c http://ftp.gnu.org/gnu/binutils/$BINUTILS.tar.bz2 && tar xvjf $BINUTILS.tar.bz2 && cd build-binutils && ../$BINUTILS/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --with-system-zlib --with-gnu-as --with-gnu-ld --disable-nls --with-float=soft --disable-werror && make $PARALLEL all && make install && cd ..) || exit 1;
##rm -rf $BINUTILS $BINUTILS.tar.bz2
 
# Section 2: GCC, step 1.
(wget -c ftp://ftp.gnu.org/gnu/gcc/$GCC/$GCC.tar.bz2 && tar xvjf $GCC.tar.bz2 && cd build && ../$GCC/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --enable-languages="c,c++" --with-system-zlib --with-newlib --without-headers --disable-shared --with-gnu-as --with-gnu-ld --with-float=soft --disable-werror && make $PARALLEL all-gcc && make install-gcc && cd .. && rm -rf build/*) || exit 1;
##rm -rf $GCC.tar.bz2
 
# Section 3: Newlib.
(wget -c ftp://sourceware.org/pub/newlib/$NEWLIB.tar.gz && tar xvzf $NEWLIB.tar.gz && cd build && ../$NEWLIB/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --with-gnu-as --with-gnu-ld --disable-nls --with-float=soft --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;
##rm -rf $NEWLIB $NEWLIB.tar.gz
 
# Section 4: GCC, step 2. Yes, this is necessary.
(cd build && ../$GCC/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --enable-languages="c,c++" --with-system-zlib --with-newlib --disable-shared --with-gnu-as --with-gnu-ld --with-float=soft --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1
##rm -rf $GCC
 
# Section 5: GDB.
(wget -c ftp://ftp.gnu.org/gnu/gdb/$GDB.tar.bz2 && tar xvjf $GDB.tar.bz2 && cd build && ../$GDB/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;
##rm -rf $GDB $GDB.tar.bz2
 
# Section 6: elf2flt.
cat > Ndless-elf2flt.patch << EOF
91a92,97
> #define R_ARM_CALL    28
> #define R_ARM_JUMP24  29
> #define R_ARM_TARGET1 38
> #define R_ARM_V4BX    40
> #define R_ARM_TARGET2 41
> #define R_ARM_PREL31  42
647a654,660
>                               case R_ARM_NONE:
>                               case R_ARM_PREL31:
>                               case R_ARM_TARGET1:
>                               case R_ARM_TARGET2:
>                               case R_ARM_CALL:
>                               case R_ARM_V4BX:
>                               case R_ARM_JUMP24:
EOF
 
(cvs -z3 -d:pserver:anonymous@cvs.uclinux.org:/var/cvs checkout -P elf2flt && patch elf2flt/elf2flt.c Ndless-elf2flt.patch && cd build && ../elf2flt/configure --target=$TARGET --prefix=$PREFIX -with-libbfd=../build-binutils/bfd/libbfd.a --with-libiberty=../build-binutils/libiberty/libiberty.a --with-bfd-include-dir=../build-binutils/bfd --with-binutils-include-dir=../$BINUTILS/include && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;
  • Create symbolic links to arm-linux-gnueabi-* for the different GCC tools (ld, gcc, objcopy, ...) if your installation use custom file names.

Verifying the installation

  • Open a console, and run:
$ nspire-gcc

If everything has been correctly set up you should see something similar to:

arm-none-eabi-gcc: no input files

As a convention for the next chapters, lines starting with $ are commands you should type in a console. Other lines are commands output. You may pick up a tutorial to learn the basic Unix commands before we continue.

5-minute tutorial

Your first build

Ndless comes with sample programs in the _samples/ directory of the Ndless SDK. We will try to build the C Hello World. Change the current directory of the console:

$ cd "<my_ndless_sdk_copy>/_samples/helloworld"

Check the content of the directory:

$ ls
Makefile  hello.c

A Makefile is a script which describes how to build the program. It is interpreted by GNU Make, which is run with the command make. So let's make the program:

$ make
nspire-gcc -Os -Wall -W -c hello.c
nspire-ld -nostdlib hello.o -o hello.elf
mkdir -p ../../calcbin/samples

make tells us the different commands used during the building process.

arm-none-eabi-objcopy -O binary hello.elf ../../calcbin/samples/hello.tns

nspire-gcc is Ndless's wrapper for the GNU C Compiler GCC, which compiles C and assembly source files to object files (here hello.o).

nspire-ld is the wrapper for the GNU linker ld, which combines object files to produce an executable in the ELF format (here hello.elf).

arm-none-eabi-objcopy is a GNU utility used to convert the ELF file to an Ndless-compatible executable directly runnable on a TI-Nspire. The file hello.tns can be found in src/calcbin/samples.

A C program

Let's have a look at the Hello World source code hello.c. It follows the C conventions.

It has an entry point:

int main(void) {

and a return code (required but currently ignored by Ndless and the OS):

  return 0;
}

All Ndless programs requires the standard include file, os.h:

#include <os.h>

It allows to call syscalls provided by the Operating System of the TI-Nspire. Some syscalls are functions from the C standard library, others are part of the C POSIX library. There are also functions of Nucleus RTOS on which is based the TI-Nspire OS.

We are also using the nspireio2 library provided with the SDK:

#include <nspireio2.h>

Let's now say hello with nspireio2:

	nio_console csl;
	lcd_ingray(); // because nspireio2 doesn't support colors
	clrscr(); // clear the screen
	// 53 columns, 29 rows. 0px offset for x/y.
	// Background color 0 (black), foreground color 15 (white)
	nio_InitConsole(&csl, 53, 29, 0, 0, 0, 15);
	nio_DrawConsole(&csl);
	nio_printf(&csl, "hello world!");
	wait_key_pressed();
	nio_CleanUp(&csl);

Your first program

You can copy the helloworld directory and start to adapt the source code.

If you want to create a program from scratch:

  • Create a new directory for the program
  • Type in a console:
cd "<your directory path>"
nspire-tools new <program>
where <program> is your program name. This will create a Makefile to build <program>.tns
  • Create a new .c file and edit your program
  • Run the make command to build it

Going further

  • Pick up a good C tutorial before writing your own programs
  • Learn the syntax of GNU Make's Makefiles to adapt them to your own build requirements
  • Learn to use GNU GCC features and extensions