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 "\n\n" 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
No comments:
Post a Comment