The field of satellite navigation has witnessed the advent of a number of new systems and technologies: after the landmark design and development of the Global Positioning System (GPS), a number of new independent Global Navigation Satellite Systems (GNSSs) were or are being developed all over the world: Russia's GLONASS, Europe's GALILEO, and China's BEIDOU-2, to mention a few. In this ever-changing context, the availability of reliable and flexible receivers is becoming a priority for a host of applications, including research, commercial, civil, and military. Flexible means here both easily upgradeable for future needs and/or on-the-fly reprogrammable to adapt to different signal formats. An effective approach to meet these design goals is the software-defined radio (SDR) paradigm. In the last few years, the availability of new processors with high computational power enabled the development of (fully) software receivers whose performance is comparable to or better than that of conventional hardware devices, while providing all the advantages of a flexible and fully configurable architecture. The aim of this tutorial paper is surveying the issue of the general architecture and design rules of a GNSS software receiver, through a comprehensive discussion of some techniques and algorithms, typically applied in simple PC-based receiver implementations.