In this article I plan to describe the toolchain I use for bare-metal ARM Cortex-M development. I'm not necessarily advising you to use this toolchain, but it works well for me and this article will help form the basis of various future articles about debugging and robust development.
I use the toolchain developed by ARM under the "GCC ARM Embedded" name. This is a free toolchain based on a patched version of the open source GCC compiler and GNU binutils. Since it's free and available as source, there is a good chance if you are using a free or low cost IDE or other development tool for ARM microcontrollers that it's based on this compiler.
I don't really recommend using the PPA. In development for embedded systems you should consider the compiler to be a dependency of your project and make sure that you are always using the exact same compiler for each build (that includes even minor/patch releases). Changing the compiler should be considered equivalent to changing a major library and requires a complete regression test. This is because, whilst the compiler should still produce working code that achieves the same results (that's what a device-independent language like C was designed to do), there are subtle but important changes between releases of compiler which affect things like stack usage. Compilers are constantly trading off code size, speed and run-time memory requirements and minor revisions might improve speed slightly at the expense of an extra register being pushed onto the stack. This can result in unexpected behaviour changes in embedded systems which are heavily resource constrained.
So don't stick to a compiler beyond its support lifetime if you don't need to. But only change the compiler at the start of a new development phase and make sure everyone in your team is using the specified new compiler version for best results. Archiving a compiler with a release might also be a good idea, particularly if you are committed to support that major revision for some time. It means that you can make only minor changes to the code and be sure that your produced binary won't change significantly.
GCC ARM Embedded comes with a version of Newlib which is a minimal, portable implementation of libc. This provides the familiar C language environment and functions (printf, gmtime, malloc etc.) but it needs some support from your code to hook these functions into the physical hardware (e.g. UART, RTC, atomic operations for mutex respectively). Details of how to do that will be in a future post, but it's worth understanding that the libc implementation and the compiler together are required to form a working toolchain.