diff --git a/README.md b/README.md index f04d321..46aa9ea 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,75 @@ Makefile generator for C projects. -`mgen` automatically generates build rules for all source files (extension `.c`) -it finds in a recursive search of the directory in which it is run. It reads the -varibles from your existing Makefile and uses them when generating the new -targets. +## Overview -The following varibles are supported: - - CC -> C compiler - - CFLAGS -> compilation flags - - LDLIBS -> linker libraries +`mgen` automatically generates build rules for all source files (extension `.c`) +it finds in a recursive search of the directory in which it is run. It places +the rules in your existing makefile, meaning you can easily change build options +and even write your own rules based on those generated. + +`mgen` will place the generated rules between the strings "`#=mgen_start=#`" and +"`#=mgen_end=#`" in your makefile. If these lines are not present, it will add +them to the end of the file and place the rules there. Anything not between +these lines will not be touched by `mgen`. + +`mgen` utilizes certain common make variables when generating the build rules. +These are: + + - CC -> C compiler + - CFLAGS -> compilation flags + - LDLIBS -> linker libraries - LDFLAGS -> linker flags - - TARGET -> name of final executable/library + - TARGET -> name of final executable/library + +It is therefore recommended that you set these at the beginning of your +makefile, unless you want to use the `make` defaults. + +`mgen`'s rules will place all compiled files in the `BUILD_DIR` specified on the +command line (see *Usage* section of this README). Objects will be placed in the +directory `BUILD_DIR/obj/`, and the `TARGET` will be placed at +`BUILD_DIR/$(TARGET)`. + +## Usage + +``` +$ mgen --help +Usage: mgen [OPTIONS] [BUILD_DIR] + +Arguments: + [BUILD_DIR] Directory to place build files [default: ./build] + +Options: + -p, --pretty Replace default make output with nice build messages + -m, --makefile Path to makefile [default: ./Makefile] + -h, --help Print help +``` + +Starting from a "blank slate," i.e. you have no build system configured in your +project, simply run `mgen` in the root directory and then run `make`. It's as +easy as that. + +If you already have a makefile in use, remove any rules to build the target or +object files (that what `mgen` is for). You can keep any other, more complex +rules that depend on these things, though. Then, run `mgen` and `make` and you +are good to go. + +## Build Instructions + +Build: `cargo build --release` +Install (must build first) (needs root): `sh install.sh` +Uninstall (needs root): `sh uninstall.sh` + +## Todo + +- Add functionality to generate rules to build a library, as opposed to an + executable. +- Add options to generate convenient rules like `clean` to remove all build + files, `run` to execute the target, etc. +- Don't create new makefile if no `.c` files are found. +- Add exclude directory(ies) from search +- Eventually: write man page. +- Maybe: allow build directory to be specified within the Makefile ? +- Maybe: figure out a way to only have the user run `mgen` once, then the + makefile itself will call it again if it needs to be regenerated due to a + change in project structure ? diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..fcf1cc7 --- /dev/null +++ b/install.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +cp ./target/release/mgen /usr/bin/mgen diff --git a/src/main.rs b/src/main.rs index 1b4db01..0eca580 100644 --- a/src/main.rs +++ b/src/main.rs @@ -102,6 +102,14 @@ fn main() { fs::File::create(&args.makefile).unwrap(); } + if !Path::new(&args.build_dir).exists() { + fs::create_dir(&args.build_dir).unwrap(); + } + + if !obj_dir.exists() { + fs::create_dir(obj_dir).unwrap(); + } + let mut makefile_handle = fs::OpenOptions::new() .read(true) .open(args.makefile.clone()).unwrap(); @@ -117,10 +125,11 @@ fn main() { build_rules.push_str("\n"); + // Target linking rule let target_path = build_dir.join(Path::new("$(TARGET)")); let target_path = target_path.to_str().unwrap(); - build_rules.push_str(&format!("{}: ", target_path)); + build_rules.push_str(&format!("{}:", target_path)); for file in project_files.iter() { build_rules.push_str(&format!(" {}", file.obj_path)); } @@ -130,7 +139,7 @@ fn main() { build_rules.push_str(&format!("\t@printf ':: Linking %s ... ' $(TARGET)\n")); } - build_rules.push_str(&format!("\t{}$(CC) $(LDFLAGS) -o {} ", + build_rules.push_str(&format!("\t{}$(CC) $(LDFLAGS) -o {}", if pretty {"@"} else {""}, target_path)); for file in project_files.iter() { build_rules.push_str(&format!(" {}", file.obj_path)); @@ -140,7 +149,9 @@ fn main() { if pretty { build_rules.push_str(&format!("\t@printf 'done\\n'\n")); } + // ---------- + // Rules for each object file for file in project_files.iter() { let mut build_rule = String::new(); @@ -168,6 +179,7 @@ fn main() { build_rules.push_str(&build_rule); } + // ---------- build_rules.push_str(&end_key); diff --git a/uninstall.sh b/uninstall.sh new file mode 100644 index 0000000..6d8cc03 --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +rm /usr/bin/mgen