The command to compile the main.c and greet.c files is identical, except for the name of the files involved. The simpliest and most direct way to address the problem is to define the compile task in a loop. Perhaps something like this …
Rakefile Fragment
1 SRC = FileList['*.c'] 2 SRC.each do |fn| 3 obj = fn.sub(/\.[^.]*$/, '.o') 4 file obj do 5 sh "cc -c -o #{obj} #{fn}" 6 end 7 end
Just a couple things to note about the above code.
.o (which is, after all, what we want to generate), the file list is defined in terms of the .c files. Why? The simple reason is that file lists search for file names that exist in the file system. We have no guarantee that the .o files even exist at this point (indeed, the will not after invoking the clean task). The .c are source and will always be there.
Defining tasks in a loop is pretty cool, but is really not needed in a number of simple cases. Rake can automatically generate file based tasks according to some simple pattern matching rules.
For example, we can capture the above logic in a single rule … no need to find all the source files and iterate through them.
Rakefile Fragment
1 rule '.o' => '.c' do |t| 2 sh "cc -c -o #{t.name} #{t.source}" 3 end
The above rule says that if you want to generate a file ending in .o, then you if you have a file with the same base name, but ending in .c, then you can generate the .o from the .c.
t.name is the name of the task, and in file based tasks will be the name of the file we are trying to generate. t.source is the name of the source file, i.e. the one that matches the second have of the rule pattern. t.source is only valid in the body of a rule.
Rules are actually much more flexible than you are led to believe here. But that’s an advanced topic that we will save for another day.
Here is our final resule. Notice how we use the SRC and OBJ file lists to manage our lists of scource files and object files.
Rakefile
1 require 'rake/clean' 2 3 CLEAN.include('*.o') 4 CLOBBER.include('hello') 5 6 task :default => ["hello"] 7 8 SRC = FileList['*.c'] 9 OBJ = SRC.ext('o') 10 11 rule '.o' => '.c' do |t| 12 sh "cc -c -o #{t.name} #{t.source}" 13 end 14 15 file "hello" => OBJ do 16 sh "cc -o hello #{OBJ}" 17 end 18 19 # File dependencies go here ... 20 file 'main.o' => ['main.c', 'greet.h'] 21 file 'greet.o' => ['greet.c']