x
Loading
 Loading
Hello, Guest | Login | Register
Compile Time
Live Random or DieHarder
Simulations, games, encryption, and statistical analyses all need random numbers. But just how random is your random number generator? DieHarder can help.
Chewing on Progress Bars
Implement a nifty progress bar with a handful of modules and a smattering of code.
CMake: Make Reloaded
cmake is a portable build system: Create a single source definition and build your code on one or many platforms. Learn how to use cmake and see how KDE uses the tool for the project’s next generation build system.
Embracing the Git Index
Linus Torvalds once said, "If you deny the Index, you really deny git itself." (February 4, 2006, Git List Archives). Rather than try to sweep the mysteries and complexities of the git Index under the rug, some explanation and examples can help clarify it, expose its power, and allow you to revel in it!
How To Git It
You've heard about it. You've read about it. But maybe you just don't *cough* git it yet. Linus converted to git, now you can too with this overview.
Programming Linux 2.6
Kernel 2.6 is finally here, and it touts several enhancements over the 2.4 series. The press has highlighted changes relevant to systems architects and managers, but there's plenty in 2.6 for application developers, too.
Exposing your APIs to Python
April's "API Spy" introduced Python's C API and showed how a Python interpreter can be embedded in a C program. For many tasks where you need to run a Python script from within C code, last month's technique is sufficient. However, as your C programs and Python scripts evolve, you may want or need more advanced interaction between the two languages.
Changing a Program's Identity
If you've worked with Linux for some time, you've probably used a set-user ID (or setuid) program to temporarily gain permissions different from your normal access rights. Unlike typical programs that run with your permissions, a setuid program runs with the permissions of that program's owner. For example, if you launch a program that's setuid and owned by root, that program runs as though root had executed it, temporarily granting you the same (full) access privileges as the superuser.
Embedding Python in C Applications
Many applications, including most of those shipped with Windows, Linux, KDE, Gnome, and Apache are written in C. C is perhaps the most universal of all programming languages -- its expressive power, portability, minimalism, and speed make it a popular choice.
Writing a Trace System
Unix is traditionally very text-oriented: configuration files are plain ASCII, commands are issued via the shell, tools provide feedback via stdout, and daemons and other system services record status in logs.
Software Packaging with RPM
If you're running RedHat or a Linux distribution based on RedHat, chances are you've had occassion to use RPMs. RPMs and Red Hat's accompanying package management system (and other systems like it) greatly simplify the task of maintaining the software on a system. With RPMs, installs, upgrades, and even downgrades are quick and easy.
Programming with Qt, Part 3
In this third and final installment on introductory Qt programming, let's take a look at two graphical development tools that are part of the Qt framework: the GUI editor Qt Designer and the foreign language translation tool Qt Linguist.
Programming with Qt, Part 2
In the previous installment of this series, we implemented two very simple example programs, which nevertheless demonstrated quite a few of the core concepts of Qt programming. This month, let's will take a step back and look at some of the fundamentals of programming with Qt.
Programming with Qt, Part 1
Qt is a set of C++ libraries and development tools commercially developed and distributed by Trolltech of Norway. Qt is available for different platforms (Win32, most flavors of Unix/Linux, as well as Mac OS X), and in several editions, including the Free Edition that's free of charge for the development of free and open source software. Trolltech's Free Edition has all of the same features of its Enterprise Edition -- at no cost!
Embed SQL with SQLite
Suppose that you want to contact a company that you've found on the Internet, but you don't know where it's located, and the only contact information provided on the "About the Company" web page contains a phone number with the unfamiliar area code of 323. You could call them up, hope to reach a real person, and ask where the company is located. Or, you could look up what geographical region uses that area code. Using everyone's favorite search engine, and within a few clicks, you see that 323 is a new area code for Los Angeles. Problem solved, and time to move on.
Building a Universal SQL Client
The Qt (sometimes pronounced "cute") C++ toolkit has been available since 1995, but it entered the mainstream of the computer programming world just a few years ago. Known for its first-class support of Unix operating systems, Qt, from Norwegian company Trolltech, surged in popularity along with the growth of Linux. Developers have turned to the toolkit for its cross-platform features alone: Qt helps you build Macintosh and Windows programs directly from your Linux source code. Qt also received a boost from the ever-popular KDE, which relies heavily on the toolkit to simplify GUI programming. Even the Linux kernel now requires Trolltech's libraries for its xconfig build module. As a result, Qt has cemented a spot among the best-selling C++ toolkits on the market.
Wizardly Words for Warnings
When building someone else's software, there's nothing more demoralizing than seeing whole rafts of compiler warnings fly by. A common reaction to such spewage is, "Are these real issues requiring investigation, or is this just the handiwork of a sloppy developer?" Not all warnings indicate problems with code, but there's no way to know for certain without actually looking at each and every warning. Needless to say, when warnings turn out to be nothing, it's downright frustrating -- and a huge waste of time. So, professional developers not only work hard to eliminate compiler warnings, they ask the compiler to produce more of them. Why? There are three very good reasons:
Analyzing Code Coverage with gcov
Before releasing any amount of code, developers usually test their work to tune performance and prove that the software works as intended. But often, validation is quite difficult, even if the application is simple.
Debugging Memory Problems
Dynamic memory allocation seems straightforward enough: you allocate memory on demand -- using malloc() or one of its variants -- and free memory when it's no longer needed. Indeed, memory management would be that easy -- if only we programmers never made mistakes. Alas, we do make mistakes (from time to time) and memory management problems do occur.
Living the Dynamic Life of Plg-Ins
Many C and C++ applications use a plug-in or modular architecture to add features dynamically. Unlike monolithic applications, where all features are compiled into a single executable, modular applications typically have a central engine and a set of complementary feature libraries. Each library -- usually called a plug-in or a module -- implements a unique feature. When that specific feature is needed, the engine simply loads the module on demand, and calls the module to do the work.
Finding and Defining Features
In September, we discussed the significant advantages of re-implementing desired, but less common functions: if you use a feature of your local operating system, but discover it doesn't exist on other platforms, write your own implementation, and make that code a part of your distribution.
Building Portable Build Systems
Last month, we talked about writing portable code and focused on how to use feature test macros, coding standards, and emulation of uncommon functions to make porting even easier. This month, we'll talk about portable build systems -- tools you can use to easily build that portable code on a variety of target platforms.
Writing Portable Code
Everyone professes to write portable code, but few programmers actually manage to do it. In most cases, so-called portable code comes out littered with #ifs or #ifdefs (or worse, nested #ifs and #ifdefs), rendering the code illegible and obfuscated. Sadly, the lion's share of many porting efforts is spent trying to figure out which lines of code are actually being compiled and executed. This wastes time and energy, and can be downright frustrating.
Compilers, Part 3: The Back End
This month, we finish peeking under the hood of the compiler with a look at the last two steps in the compilation process (the process that turns your source code into something that a machine can actually execute). If you recall, there are seven steps in compilation. These steps are shown in Figure One. Last month, we looked at step five, "Intermediate Code Optimization", those optimizations that the compiler can perform independent of the architecture of the target machine.
Compilers, Part 2: The Back End
Last month, we began investigating how compilers actually work. Our look "under the hood" started with the front end of the compiler -- the phases that parse and tokenize the source file, verify syntax and semantics (the rules of the programming language), and translate the source code into an intermediate representation. Figure One shows a overview of the entire process. This month, we pick up the discussion at step five, "Intermediate Code Optimization".
Compilers: The Front End
Over time, this column has discussed many programming topics and techniques. However, one subject we have never fully addressed is what actually happens at "compile time." How does a compiler take the program you write and translate it into something that a machine can understand and execute?
Linux and Executables
For the past few months, we've been learning how the compiler and linker work together to take the programs you write and convert them into executables that the operating system can run. We've followed the process from source code to object module to executable, with static and shared libraries thrown in as well.
Building and Using Shared Libraries
Over the past several months, this column has shown you how to use gcc and g++ language extensions, how to link objects and functions, and how to build executables. We will continue this month with a discussion about a very specific type of object -- a shared (or dynamic) library -- and how to take advantage of it in your programs.
Building the Perfect Executable
Your program has compiled with no errors. You type its name and watch it run. It seems so simple, but there's a lot that had to happen behind the scenes at the time the program was compiled in order to make it look so easy. For one thing, in order to make it possible for the kernel to properly load and execute your program, the compiler toolchain has to know exactly how the kernel will expect the new process's virtual address space to look. In other words, the toolchain has to be able to build the executable according to specifications that the kernel understands and expects.
Compiling and Linking: Under the Hood
These days, interpretive languages, most notably Perl, JavaScript, and Python, have made the barriers to entry for newly-aspiring programmers a lot lower than they once were. Perl, in particular, makes it easy for a newcomer to get his or her feet wet and leave the deeper mysteries that make for industrial-strength, high-performance software for later on. Languages such as C and C++ that typically get compiled all of the way down to real machine code are a different story, however. These languages, designed by professional software engineers for professional software engineers, generally assume that you, the programmer, are able to get down to the gritty details (and often idiosyncratic quirks) of the underlying hardware and the software development tool set you will be using.
Working with Language Extensions
Many of you are familiar with the C and C++ languages. You know the syntax and the semantics of the various operations and have a feel for what is allowed by the language according to its specification. However, you may (or may not) be surprised to discover that compilers for these languages deviate from the official specifications.
The Insides of Networking
In the past two months, this column has introduced some of the functions necessary for writing networked programs. We've been throwing around terms like TCP, UDP, IP, and others without any real description of what they mean. This month, you should gain a better understanding of these abbreviations and exactly what is going on when they are used to communicate between machines. With this knowledge, you will be better equipped to determine exactly which protocol is appropriate for your applications -- for instance, why UDP is often used for broadcast-style transmissions, while TCP is used for transactions.
More Network Programming
Last month we started a discussion on network programming. However, in the interest of getting through an entire example of a client and a server and how they communicate, we omitted many details. This month, we'll examine our examples more closely to gain more knowledge about network programming. Specifically, we will discuss how to get IP addresses from hostnames and hostnames from IP addresses. We will also take a look at the difference between little-endian and big-endian machines and find out why "endianness" matters in network programming.
Network Programming
This month, we are starting a series on network programming. This area of programming is enormous, not only because of the sheer amount of information that is needed to successfully develop network applications, but also because of the number of applications currently being developed with networking in mind. With network speeds increasing, more and more applications have a "network" version of some sort. For example, Quicken can automatically update your account information from some banks, computer games can be played with other people on the Internet, and so on.
A Peek Inside the Clock
Last month we introduced a few functions that allow your applications to retrieve the current time from Linux. We discussed how one might implement a simple function that causes an application to wait for a specific amount of time before continuing execution. We also looked at the alarm() function, which keeps time for you, and how you might use alarm() instead of the timing functions to allow a program to wait for a specific amount of time without needlessly executing any instructions while waiting.
Time Functions
Every now and then, you'll find that in the midst of an application, you really need to know the time from the system clock. Even more likely, you need to have your application wait for a specific amount of time. Linux's timing functions are relatively straightforward; however, most people overlook them until they need to use one in an application.
Dynamic Memory Allocation -- Part II
Last month we introduced some of the concepts that are involved with memory management. We discussed how to dynamically allocate memory in your applications. We also described the various methods that allocators use to manage free memory. This month we turn our attention to memory allocation at a lower level -- the level of the operating system.
Dynamic Memory Allocation -- Part I
This month we're going to examine a topic that is probably familiar to those of you who have any experience with programming -- dynamic memory allocation. In any programs of significant heft, dynamic memory management is a necessity. You are probably experienced with the standard C functions malloc() and free(), and we'll do a brief recap of those memory allocation and deallocation functions. Following that, we will look at how memory allocation in Linux actually works.
The Fibers of Threads
For the last several months in this column, we've been looking at programming with Linux's threads library, pthreads. However, we have taken for granted the work that is actually done under the covers by the pthreads libraries. So this month's Compile Time will dissect Linux pthreads themselves to discover exactly what it is that makes them tick.
Threads and Mutexes -- Part II
Welcome to the second part of our look at programming with threads. In last month's column we talked about the functions that allow you to create and wait on threads. This month we're going to dive deeper into the problems that often arise when using threads to write concurrent programs. Before we begin that however, we'll return to the ticket agent example we looked at last month and discuss the solution to the problem of over-selling of tickets.
« Prev |
Follow Linux Magazine
Rackspace