New toy..

Managed to get some nice time off today, read some of the library books, watched Tron, Ghost Busters I, and Spaced Invaders, but most of all got to relax. I’ve also placed my VIMRC file into a cvs repository on my OpenBSD box, that should make syncing changes with my Desktop/Laptop easier, plus allow me to see what I’ve changed hehe.

Had an interesting idea and started playing with some Ruby today also.

Normally when I start a new program I make a new directory in ~/code/Lang/src/ and copy a template makefile over from ../../makefiles/ and edit it to my needs. In one of the library books, I found a GNU Makefile that essentially automates building a C/C++ program where by all C/C++ source files (subject to make handling the dependencies) are compiled into corresponding files and get linked together into the binary, nice little thing when you look at it. With a little tinkering it could probably be made semi-language independent but I don’t really have time to dig into GNU Make’s syntax and features to do that.

I’ve basically written makefiles in the past that should work with just about any ol’make program. For much the same reason I write shell scripts that should run on most any /bin/sh, because I don’t want to edit the freaking thing if I ever meet a Unix like OS it won’t run on lool.

The idea I had was a enlazynating program that by knowing a fair bit about a given languages normal build process (such as C, C++, and Java), it could then automate the process of building it without having to generate a makefile, kind of like a ‘smart-makefile’ of sorts. I’ve got a alias set in my shell so that gcc is called on the command line with my usual settings. I also tend to include a few more once the things done.

It’s probably a stupid idea to do this, a decent BSD or GNU Makefile would likely serve much better (and be worth the learning of each ones extensions to make). But I rather like to be able to just ‘have fun’ playing with and testing stuff.

Right now, it seems to be able to handle a simple compile/link of files in one directory but needs some work to properly link files in subdir’s, lots of other stuff to do. But working on it has been a good way to pass the time.

Currently I classify this as a toy rather then a program for serious usage. But if I ever finish it, I might use it just for the sake of keeping a fairly fast build/test cycle.

If I could, I would’ve made a machine to manage VHS-Tape/DVD-Disk changing but hey, I’m not an inventor when it comes to to building some thing out of thin air…

Here is what I’ve done over the past couple hours, it’s not very good but it’s a starting point for later play.

#!/usr/local/bin/ruby -w
# usage: make [opt] project [dir]
# TODO:
# rdoc...
# handle header files and linking properly in C
# support more then C
# implement a way to set lang opts/debug/profiler stuff correctly
# reduce usage of $globals
# clean up code... looks like sludge

require 'getoptlong'
require 'rdoc/usage'

$lang=nil
$project=''
$startdir=Dir.pwd
$debug=false
$profiler=false
$verbose=false

def main()

opts = GetoptLong.new(
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
[ '--lang', '-l', GetoptLong::REQUIRED_ARGUMENT ],
[ '--lang-opts', '-o', GetoptLong::REQUIRED_ARGUMENT ],
[ '--debug', '-d', GetoptLong::OPTIONAL_ARGUMENT ],
[ '--prof', '-p', GetoptLong::OPTIONAL_ARGUMENT ],
[ '--clean', '-c', GetoptLong::NO_ARGUMENT ],
[ '--verbose', '-v', GetoptLong::NO_ARGUMENT ]
)

begin
opts.each do |opt, arg|
case opt
when '--help'
RDoc::usage()
when '--lang'
proc_lang( arg )
when '--lang-opts'
puts "#{arg} -> --lang-opts not implemented!"
when '--debug'
$debug = true
when '--prof'
$profiler = arg
when '--verbose'
$verbose=true
end
end

if ARGV[0]
$project = ARGV[0]
end
if ARGV[1]
$startdir = ARGV[1]
end
puts ARGV #debug
puts "nn"
n=LangC.new()
n.make()

unless $lang
$stderr.puts( 'WARNING: --lang not set!, defaulting to ISO C99' )
end

# call usage() on *any* error and print the problem
rescue StandardError
puts( $! )
RDoc::usage()

end

end

def proc_lang( str )

case str
when 'c','C'
# set up for C
$lang=str
when 'c++','cpp','C++','C++','cc','CC','cxx','CXX'
# set up for C++
when 'java','Java'
# set up for Java
when 'Perl','pl', 'plx'
# Setup for Perl
when 'Python','py'
# Setup for Python
when 'Ruby','rb'
# set up for Ruby ;-)
end
end

class Lang

def make()
end

def each( startdir, &block )
dp = Dir.open(startdir) do |dir|
dir.each do |node|
if node == '.' or node == '..'
next
end
p = File.expand_path( node, startdir )
yield( p )
if File.directory?( p )
self.each( p, &block )
end
end
end
end

end # !class Lang


class LangC < Lang

@@compiler = 'gcc'
@@cflags = "-Wall -Wpointer-arith -Wcast-qual -Wcast-align " +
"-Wconversion -Waggregate-return -Wstrict-prototypes " +
"-Wmissing-prototypes -Wmissing-declarations " +
"-Wredundant-decls -Winline -Wnested-externs " +
"-std=c99 -march=i686 -pipe "
@@ldfags = nil
@@debug = '-g'
@@prof = nil
@filelist = Array.new()

# The very bloody boring constructor which serves only to override the
# defaults for our static class variables.
#
def initialize( compiler=false, cflags=false, ldflags=false,
debug=false, prof=false )

if compiler then @@compiler = compiler end
if cflags then @@cflags = cflags end
if ldflags then @@ldfags = ldflags end
if debug then @@debug = debug end
if prof then @@prof = prof end
@@ldflags=nil;@@prof=nil#debug

end

# Assemble project
def make()

@filelist = Array.new()
self.compile()
self.link()

end

# Walk the directory tree and compile all .c files into .o
#
def compile()

$stdout.puts '------- COMPILING -------' if $verbose

self.each( $startdir ) do |file|
if file =~ /.*.c$/
p = file.to_s.gsub( File.extname(file),".o" )
@filelist.push( p )
# Don't compile unless the source is newer then the object files
if File.exists?( p )
next unless timecheck(file,p)
end

system( "#{@@compiler} #{@@cflags} #{@@debug} #{@@prof} " +
"#{file} -c -o #{p}" )
end
end
end

# Walk the directory tree and link all object files
def link()

$stdout.puts '------- LINKING -------' if $verbose

@filelist.each do |obj|
system( "#{@@compiler} #{@@cflags} #{@@ldflags} #{@@debug} " +
"#{@@prof} #{obj} -o #{$startdir}/#{$project}" )
end
end

# Return true if first filename has a newer time stamp then the second
#
def timecheck( f1, f2 )
File.mtime( f1 ) > File.mtime( f2 ) ? true : false
end

end

if __FILE__ == $0
main()
end