-
Notifications
You must be signed in to change notification settings - Fork 2
Portable programmable build system
License
quietfanatic/make-pl
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
MakePl - Very portable build system in Perl https://github.com/quietfanatic/make-pl [About] Don't make your users type more than one command to build. Don't make your users download and install some obscure build system. Program your build system in a real programming language. ./make.pl && run [Installation] Just clone this repo and stuff it in your project directory. This has no dependencies besides Perl >= 5.10 and its core modules. Alternatively, use this repo as a git submodule. [Usage] To run a make.pl: - ./make.pl <options> <targets> To generate a bare-bones make.pl: - perl MakePl.pm <directory (defaults to .)> [Quick Reference] make; - Put this at the end of the script, whether standalone or included. rule <targets>, <dependencies>, <routine>, <options>? - Defines a compilation rule like in a Makefile. - <targets> can be a single filename or an array ref of filenames. - <dependencies> can be a single filename, an array ref of filenames, or a subroutine which returns filenames. - The compile routine (AKA the recipe) is given two array refs as arguments containing the targets and the dependencies. - Here are the available options: fork => 1 - This rule can be run in parallel (in a forked child process). gendir => 1 - Automatically generate the directory structures of all targets of this rule. suggested => 0|1 - This rule's targets will show up (or not) in the Suggested Targets list in the --help message. phony <targets>, <dependencies>?, <routine>?, <options>? - like rule, but the target(s) do not correspond to actual files subdep <targets>, <dependencies> - Establishes that anything that depends on the target(s) also depends on the given dependencies, e.g. because of an #include statement. subdep <routine> - Provides a way to automatically deduce subdeps. The routine will be called with a filename and is expected to return some more filenames. See "sample_make.pl" in this repo for a function that'll scan C/C++ files for #include statements. defaults <targets...> - With no arguments, make.pl will build these targets. The default default is to run the first rule given in the workflow. targets - Returns all files or phonies that are the target of any rule that has been declared so far. exists_or_target <filename> - Checks if the file exists or there's a target for it. include <filenames...> - Include the targets and rules in another make.pl. Relative filenames, working directories, etc. all do The Right Thing. Cyclical includes are fine and even encouraged. config <filename>, <var>, <routine>? - Associate a config file with a data structure. The file will immediately be read into the reference, and a rule will be established for later to write to the config file if the data has changed. The optional routine will be called before the file is written if it is determined to need writing. option <name>, <routine>, <description>? - Allows an option to be specified on the command line, like "--<name>" or "--<name>=<value>". <routine> can be a code ref, which will be called with <value> when the option is provided, or a scalar ref, which will be set to <value> when the option is provided. The optional one-line description will be printed in the "--help" message. The description should start with "--<name>". chdir <directory> - Please use this instead of CORE::chdir or Cwd::chdir. run <command> - Like the builtin system(), but aborts the build process if the command gives a non-zero exit status. slurp <filename>, <length>?, <fail>? - Just returns the contents of the file as a string. If <length> is given, it only reads the first <length> bytes. Dies on failure unless <fail> is provided and false. splat <filename>, <string>, <fail>? - Writes the string to the filename, clobbering any previous contents. Dies on failure unless <fail> is false. slurp_utf8 <filename>, <length>?, <fail>? splat_utf8 <filename>, <string>, <fail>? - Like slurp and splat, but with UTF-8-encoded files. which <command> - Like 'which' on UNIX and 'where' on Windows. Searches the PATH for the executable file providing the given command and returns it, or undef if it wasn't found. canonpath <filename> - Gets rid of extraneous ..s and things like that. Also changes all \s into /s. rel2abs <filename>, <base>? abs2rel <filename>, <base>? - Convert between relative and absolute filenames, relative to cwd if <base> is not provided. [Working Directories] MakePl tries to make working directories a lexical concept, so that things just work how you expect them to. - All relative filenames given to the API are relative to the current working directory. - When you import MakePl, the working directory is always set to the same directory that the make.pl is in, no matter where you invoked it from. - All recipes will be run in the same working directory that the rule was defined in. - Even if one make.pl includes another make.pl, each uses filenames relative to its own directory. That is, if ./make.pl says "modules/cake/lime" and modules/cake/make.pl says "lime", they are talking about the same file. - Filenames given on the command line are relative to the current working directory of the command line, not of the make.pl. - If you want to manually change directories, use the chdir provided by this module. Using CORE::chdir will desync $ENV{PWD}. [Recommendations] - It's best to die if something fails. The autodie pragma is useful. - A basic knowledge of Perl is recommended. Knowledge of make and Makefiles is not required, but knowledge of why people use them is. - If your program is large and has good modularity, do take advantage of the include functionality. If two make.pl files mutually include one another, you can invoke either one to do stuff; the following commands would be equivalent: $ ./make.pl modules/cake/lime $ modules/cake/make.pl modules/cake/lime $ cd modules/cake; ./make.pl lime This does cause one counterintuitive effect. If you want to use a phony target belonging to a make.pl in a different directory, you must prefix the phony target with that directory (as if it's actually a file). $ modules/cake/make.pl clean # oops, this cleans the whole project $ modules/cake/make.pl modules/cake/clean # just clean the cake $ ./make.pl modules/cake/clean # this works too - After the previous point it goes without saying, but you can invoke a make.pl from any directory, not just the one it's in, provided the make.pl is correctly formed. To make sure your make.pl can be run anywhere, put use lib do {__FILE__ =~ /^(.*)[\/\\]/; ($1||'.')◀path▶}; use MakePl; where ◀path▶ is nothing if MakePl.pm is in the same directory, or something like .'/tools' if MakePl.pm is in the directory 'tools'. If you used 'perl MakePl.pm' to generate a make.pl, it'll have done this for you. - Because your build script is in a real programming language and not a DSL, you can actually do real abstraction. Take a look at "sample_make.pl" to see how. - This module is entirely symlink-ignorant. If you use functions that reduce symlinks like Cwd::realpath, you may cause confusion. - This won't work if you have filenames with backslashes in them. I haven't decided whether this is a bug or a feature. [BONUS] - If you use MakePl::C, the build system will follow #include "file" directives in your C and C++ files, so if you update a header, all files that include it will be rebuilt. It will not follow #include <file> directives.
About
Portable programmable build system
Resources
License
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published