diff options
author | kennyballou <kballou@onyx.boisestate.edu> | 2013-01-21 18:16:57 -0700 |
---|---|---|
committer | kennyballou <kballou@onyx.boisestate.edu> | 2013-01-21 18:16:57 -0700 |
commit | 170d169baff41b5643650f79ddc8209dae6dce6c (patch) | |
tree | 1b1a01fd479c844e6a181ccac3b37314e71d6760 | |
parent | 9b7f8a34ae8a79ec4b099140a7536976cf6a510e (diff) | |
parent | 14f2fef895ce38c53bbe629fd2449ba02c9dac07 (diff) | |
download | xnt-170d169baff41b5643650f79ddc8209dae6dce6c.tar.gz xnt-170d169baff41b5643650f79ddc8209dae6dce6c.tar.xz |
Merge branch 'refactor_build_modules'
Conflicts:
.gitignore
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | README | 14 | ||||
-rw-r--r-- | docs/source/buildreference.rst | 110 | ||||
-rw-r--r-- | docs/source/index.rst | 1 | ||||
-rw-r--r-- | docs/source/taskreference.rst | 28 | ||||
-rw-r--r-- | xnt/build/ant.py | 30 | ||||
-rw-r--r-- | xnt/build/cc.py | 73 | ||||
-rw-r--r-- | xnt/build/make.py | 17 | ||||
-rw-r--r-- | xnt/build/nant.py | 30 | ||||
-rw-r--r-- | xnt/tests/compilercollectiontests.py | 121 |
10 files changed, 328 insertions, 97 deletions
@@ -4,4 +4,5 @@ dist **MANIFEST bin +docs/build Xnt.egg-info @@ -1,4 +1,4 @@ -.. # vim: set colorcolumn=70:textwidth=69 +.. # vim: colorcolumn=70:textwidth=69:syntax=rst: === Xnt @@ -106,7 +106,7 @@ PyPi/ Pip To install from PyPi_, you will need `pip`_. Once you have ``pip``, you may only run:: - $ pip install Xnt [--user] + $ pip[2] install Xnt [--user] Linux/ Unix ----------- @@ -133,7 +133,7 @@ Here is a simple ``build.py``:: from xnt import target from xnt.tasks import * - from xnt.builders import ant + from xnt.build import make @target def init(): @@ -142,7 +142,7 @@ Here is a simple ``build.py``:: @target def build(): init() - ant("build") + make.ant("build") @target def clean(): @@ -187,9 +187,9 @@ or: * Nothing; if no target is specified, Xnt will attempt to invoke the ``default`` target -* ``help``: if this 'special' target is provided, Xnt will print all - targets marked by the ``@target`` decorator and possibly their - docstrings if they are defined +* ``list-targets``: if this 'special' target is provided, Xnt will + print all targets marked by the ``@target`` decorator and possibly + their docstrings if they are defined For more information about Xnt and the build in functions, see the `Package Documentation`_. diff --git a/docs/source/buildreference.rst b/docs/source/buildreference.rst new file mode 100644 index 0000000..704c812 --- /dev/null +++ b/docs/source/buildreference.rst @@ -0,0 +1,110 @@ +=============== +Build Reference +=============== + +Xnt has several "build" modules to aid you in your compliation and project/ +sub-project build steps + +Overview +======== + +* `Make`_ + +* `Compiler Collection`_ + +Make +==== + +Apache Ant +---------- + +.. _xnt.build.make.ant: +.. function:: ant(path="", target="") + + Invoke Apache Ant in either the current working directory or the specified + directory using the empty (default) target or the specified target. + +Gnu Make +-------- + +.. _xnt.bulid.make.make: +.. function:: make(path="", target="") + + Invoke Gnu Make (*make*) in either the current working directory or the + specified directory using the empty (default) target or the specified + target. + +(.NET)Ant +--------- + +.. _xnt.build.make.nant: +.. function:: nant(path="", target="") + + Invoke NAnt in either the current working directory or the specified + directory using the empty (default) target or the specified target. + +Compiler Collection +=================== + +For all compilers so far, Xnt assumes they are installed and in your `$PATH`. +If they are not, an error will be thrown (by subprocess) + +gcc/g++ +------- + +.. _xnt.build.cc.gcc: +.. function:: gcc(src, flags=[]) + + Compile `src` with the `gcc` to the default `out` (:ref:`defaultOut`) of + that source. Passing `flags` as given. + +.. _xnt.build.cc.gcc_o: +.. function:: gcc_o(src, o, flags=[]) + + Compile `src` with `gcc` to the out file specified by `o`. Passing `flags` + as given. + +.. _xnt.build.cc.gpp: +.. function:: gpp(src, flags=[]) + + Compile `src` with `g++` to the default `out` (:ref:`defaultOut`) of that + source. Passing `flags` as given. + +.. _xnt.bulid.cc.gpp_o: +.. function:: gpp_o(src, o, flags=[]) + + Compile `src` with `g++` to the out file specified by `o`. Passing `flags` + as given. + +Javac +----- + +.. _xnt.build.cc.javac: +.. function:: javac(src, flags=[]) + + Compile `src` with `javac` to the default out file for the source. Passing + `flags` as given. + +Notes +----- + +.. _defaultOut: + +Default out +~~~~~~~~~~~ + +Most, if not all, compilers have a default name given to compiled binaries when +no output file name is given. For example, `gcc` will give code with a `main` +method a name of `a.out` or `%.o` for objects, and so on. `javac` defaults to +`<class-name>.class`. + +.. _recompile: + +Recompile +~~~~~~~~~ + +At the current moment, all compile wrappers do not do "smart" checks for +compilation. That is, *all* compile steps will `rebuild` regardless if the +binary file is modified later than the source file. This would be a nice +feature, but I fear it would be too expensive (complicated) and out of the +scope of this project to implement correctly. diff --git a/docs/source/index.rst b/docs/source/index.rst index 6ebb18e..6e1462c 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -28,6 +28,7 @@ Contents: buildfile taskreference + buildreference Motivation ========== diff --git a/docs/source/taskreference.rst b/docs/source/taskreference.rst index c303b5f..1c5fbe8 100644 --- a/docs/source/taskreference.rst +++ b/docs/source/taskreference.rst @@ -114,34 +114,6 @@ Compile Tasks Invoke Python setup.py given the list of *commands* (or options) in the current directory or in a different directory, specified by *dir*. -Apache Ant ----------- - -.. _xnt.build.ant.ant: -.. function:: ant(path="", target="") - - Invoke Apache Ant in either the current working directory or the specified - directory using the empty (default) target or the specified target. - -Gnu Make --------- - -.. _xnt.bulid.make.make: -.. function:: make(path="", target="") - - Invoke Gnu Make (*make*) in either the current working directory or the - specified directory using the empty (default) target or the specified - target. - -(.NET)Ant ---------- - -.. _xnt.build.nant.nant: -.. function:: nant(path="", target="") - - Invoke NAnt in either the current working directory or the specified - directory using the empty (default) target or the specified target. - SCM Tasks ========= diff --git a/xnt/build/ant.py b/xnt/build/ant.py deleted file mode 100644 index 46de16b..0000000 --- a/xnt/build/ant.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -# Xnt -- A Wrapper Build Tool -# Copyright (C) 2012 Kenny Ballou - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import os -import subprocess - -def ant(path="", target=""): - cmd = ["ant", target] - if path and os.path.exists(path): - oldPath = os.path.abspath(os.getcwd()) - os.chdir(os.path.abspath(path)) - result = subprocess.call(cmd) - if oldPath: - os.chdir(oldPath) - return result diff --git a/xnt/build/cc.py b/xnt/build/cc.py new file mode 100644 index 0000000..e4592ca --- /dev/null +++ b/xnt/build/cc.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +# Xnt -- A Wrapper Build Tool +# Copyright (C) 2012 Kenny Ballou + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +""" +Common Compilers +""" + +import os +import logging +import sys +from xnt.tasks import call + +logger = logging.getLogger(__name__) + +def gcc(src, flags=[]): + """gcc compiler, non-named output file""" + return _gcc(src, flags) + +def gpp(src, flags=[]): + """g++ compiler, non-named output file""" + return _gcc(src, flags, "g++") + +def gcc_o(src, o, flags=[]): + """gcc compiler, with output file""" + return _gcc_o(src, o, flags) + +def gpp_o(src, o, flags=[]): + """g++ compiler, with output file""" + return _gcc_o(src, o, flags, "g++") + +def javac(src, flags=[]): + """Javac: compile Java programs""" + logger.info("Compiling %s", src) + cmd = __generateCommand(src, flags, "javac") + return __compile(cmd) + +def _gcc(src, flags=[], compiler="gcc"): + logger.info("Compiling %s", src) + return __compile(__generateCommand(src, flags, compiler)) + +def _gcc_o(src, o, flags=[], compiler="gcc"): + logger.info("Compiling %s to %s", src, o) + cmd = __generateCommand(src, flags, compiler) + cmd.append("-o") + cmd.append(o) + return __compile(cmd) + +def __generateCommand(src, flags=[], compiler="gcc"): + cmd = [compiler, src] + for f in flags: + cmd.append(f) + return cmd + +def __compile(cmd): + return call(cmd) + +def __is_newer(a, b): + return os.path.getmtime(a) > os.path.getmtime(b) diff --git a/xnt/build/make.py b/xnt/build/make.py index 1fa0f3f..a9339a4 100644 --- a/xnt/build/make.py +++ b/xnt/build/make.py @@ -18,13 +18,26 @@ import os import subprocess +import logging + + +def ant(path="", target=""): + cmd = ["ant", target] + return __run_in(path, lambda: subprocess.call(cmd)) def make(path="", target=""): cmd = ["make", target] + return __run_in(path, lambda: subprocess.call(cmd)) + +def nant(path="", target=""): + cmd = ["nant", target] + return __run_in(path, lambda: subprocess.call(cmd)) + +def __run_in(path, f): + oldPath = os.path.abspath(os.getcwd()) if path and os.path.exists(path): - oldPath = os.path.abspath(os.getcwd()) os.chdir(os.path.abspath(path)) - result = subprocess.call(cmd) + result = f() if oldPath: os.chdir(oldPath) return result diff --git a/xnt/build/nant.py b/xnt/build/nant.py deleted file mode 100644 index 0d35c90..0000000 --- a/xnt/build/nant.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -# Xnt -- A Wrapper Build Tool -# Copyright (C) 2012 Kenny Ballou - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import os -import subprocess - -def nant(path="", target=""): - cmd = ["nant", target] - if path and os.path.exists(path): - oldPath = os.path.abspath(os.getcwd()) - os.chdir(os.path.abspath(path)) - result = subprocess.call(cmd) - if oldPath: - os.chdir(oldPath) - return result diff --git a/xnt/tests/compilercollectiontests.py b/xnt/tests/compilercollectiontests.py new file mode 100644 index 0000000..ba470b7 --- /dev/null +++ b/xnt/tests/compilercollectiontests.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +# Xnt -- A Wrapper Build Tool +# Copyright (C) 2012 Kenny Ballou + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import sys +import os +import shutil +import xnt.build.cc as cc +import unittest + +#http://stackoverflow.com/questions/377017/test-if-executable-exists-in-python +def which(program): + def is_exe(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + for path in os.environ["PATH"].split(os.pathsep): + path = path.strip('"') + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + + return None + +@unittest.skipUnless(which("gcc"), "gcc is not in your path") +class gccTests(unittest.TestCase): + def setUp(self): + os.mkdir("temp") + with open("temp/hello.c", "w") as f: + f.write(""" + #include <stdio.h> + int main() { + printf("Hello, World!\\n"); + return 0; + } + """) + + def tearDown(self): + shutil.rmtree("temp") + + def test_gcc(self): + oldPath = os.getcwd() + os.chdir("temp") + cc.gcc("hello.c") + self.assertTrue(os.path.isfile("a.out")) + os.chdir(oldPath) + + def test_gcc_o(self): + cc.gcc_o("temp/hello.c", "temp/hello") + self.assertTrue(os.path.isfile("temp/hello")) + +@unittest.skipUnless(which("g++"), "g++ is not in your path") +class gppTests(unittest.TestCase): + def setUp(self): + os.mkdir("temp") + with open("temp/hello.cpp", "w") as f: + f.write(""" + #include <iostream> + int main() { + std::cout << "Hello, World!" << std::endl; + return 0; + } + """) + + def tearDown(self): + shutil.rmtree("temp") + + def test_gpp(self): + oldPath = os.getcwd() + os.chdir("temp") + cc.gpp("hello.cpp") + self.assertTrue("a.out") + os.chdir(oldPath) + + def test_gpp_o(self): + cc.gpp_o("temp/hello.cpp", "temp/hello") + self.assertTrue(os.path.isfile("temp/hello")) + +@unittest.skipUnless(which("javac"), "javac is not in your path") +class javacTests(unittest.TestCase): + def setUp(self): + os.mkdir("temp") + with open("temp/hello.java", "w") as f: + f.write(""" + class hello { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } + } + """) + + def tearDown(self): + shutil.rmtree("temp") + + def test_javac(self): + oldPath = os.getcwd() + os.chdir("temp") + cc.javac("hello.java") + self.assertTrue(os.path.isfile("hello.class")) + os.chdir(oldPath) + +if __name__ == "__main__": + unittest.main() |