gofr / gofr.go

// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.

// This parses files and dependencies as follows:
//   All files in the local subtree in a given package will be compiled into a library for that "directory/package" in the _obj directory
//     If you are referencing local packages, simply import them a if they were global.  Do not import them as ./pkgname, as this will break.
//     The caveat here, of course, is that you cannot duplicage names of existing packages.  You probably shouldn't, anyway.
//   Any package named "main" with main() in e.g. file.go will be linked into an executable with the name 'file' or the specified -b binary name
//     This, of course, means that you cannot have more than one destination binary per directory; make more directions for more binaries
//   Any files that end in _test.go are linked separately into their library and enables inclusion of the testing targets.
//     For the program to match up libraries with _test files, the _test files MUST be in the same package as the package they are testing.
//   Any package that includes "C" will be processed as a CGO package
//     I have not done any testing of multiple CGO packages or multiple files that import "C".  Weirdness may happen; let me know.
//   Any local #include before "C" that has a matching .c file will be automatically compiled as part of that CGO package
//     In other words, if you're linking against custom C code, make a header file with the same name and //#include it.  Libraries are covered below.
//   Any libraries necessary to link CGO packages (all will use the same ones, tell me if I should break this out) should be specified in --libs
//   For this to work with CGO, you need to make sure you have a Make.$(GOARCH) and a Make.$(GOOS) that have the right *CGO_LFLAGS* defined in them.  Grep for them in Make.pkg.
package main

import (

const (
	GOFR_VERSION = "gofr-v2.4.0"

var (
	// Flags for the command line
	binary   = goopt.String([]string{"-o", "--binary"}, "", "Name of binary (if not specified, will be file including main)")
	verbose  = goopt.Flag([]string{"-v", "--verbose"}, []string{}, "Show commands as they are executed", "")
	vverbose = goopt.Flag([]string{"-V", "--vverbose"}, []string{}, "Show very verbose debugging information", "")
	pretend  = goopt.Flag([]string{"-p", "--pretend"}, []string{}, "Don't actually execute any commands (use with -v to see what would be executed", "")
	clean    = goopt.Flag([]string{"-c", "--clean"}, []string{}, "Remove the object, test, and library directories before building", "")
	cleanxit = goopt.Flag([]string{"-C", "--clean-only"}, []string{}, "Same as --clean, except exits after the objects are removed", "")
	format   = goopt.Flag([]string{"-f", "--format"}, []string{"-F", "--no-format"}, "Format go source files if they do not adhere to gofmt rules", "Disable auto-formatting (the default)")
	autotest = goopt.Flag([]string{"-t", "--test"}, []string{}, "Automatically compile *_test.go files for a package and test them", "")
	ignore   = goopt.Strings([]string{"-x", "--ignore"}, "regex", "Specify regular expressions of file paths to ignore (eXclude) (can specify multiple times)")
	cgolibs  = goopt.Strings([]string{"-l", "--libs"}, "lib", "CGO Libraries (can specify multiple times)")
	install  = goopt.String([]string{"-I", "--install"}, "pkg", "Enable installation of the .a files and binaries into GOROOT and GOBIN under pkg/")
	prefix   = goopt.String([]string{"-P", "--prefix"}, "*", "Specify the installation prefix for the .a files (defaults to ${GOROOT}/pkg/${GOOS}_${GOARCH}/${PKG})")
	bprefix  = goopt.String([]string{"-B", "--bin-prefix"}, "*", "Specify the installation prefix for the binaries (defaults to ${GOBIN}/${PKG})")
	objdir   = goopt.String([]string{"-O", "--objdir"}, "_obj", "The directory to put object files into")
	libdir   = goopt.String([]string{"-L", "--libdir"}, "_lib", "The directory to put library files (ld.so) into")
	testdir  = goopt.String([]string{"-T", "--testdir"}, "_test", "The directory to put test files into")
	nobin    = goopt.Flag([]string{"-N", "--no-binaries"}, []string{}, "Suppress the creation of binaries (run in library mode, generating .a's)", "")
	printver = goopt.Flag([]string{"--version"}, []string{}, "Print version information and exit", "")

// Main program execution
func main() {
	goopt.Summary = "Compile all go souce files in the current directory tree"
	if len(goopt.Args) > 1 {
		fmt.Fprintf(os.Stderr, "Unrecognized option(s): %s\n", strings.Join(goopt.Args[1:], " "))

	if *printver {

	if *clean || *cleanxit {
		path.Walk(".", newGoDirCleaner(), nil)
		if *cleanxit {

	if *install == "" {
		fmt.Fprintln(os.Stderr, "Error: Installation package cannot be empty")

	if *prefix == "*" {
		*prefix = path.Join(GOROOT, "pkg", GOOS+"_"+GOARCH, *install)

	if *bprefix == "*" {
		*bprefix = path.Join(GOBIN, *install)

	// Parse the directory tree and get the file dependency maps
	pkgFiles, pkgDependencies, cgoPkgFiles := parseDirTree(*ignore)
	buildAndInstall(pkgFiles, pkgDependencies, cgoPkgFiles)

	if *autotest {
		testPackages(pkgFiles, pkgDependencies, cgoPkgFiles)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.