diff options
author | Ben Longbons <b.r.longbons@gmail.com> | 2013-08-05 15:41:04 -0700 |
---|---|---|
committer | Ben Longbons <b.r.longbons@gmail.com> | 2013-08-05 15:41:04 -0700 |
commit | d7bb91cd264300351e94e37a84b1de45f2312745 (patch) | |
tree | 9464fd72647146c2642ab6b493f858afcfe51566 /attoconf/lib/c.py | |
parent | 3a475005ce9f48b6bbf45a18660dbed6c4921269 (diff) | |
download | attobuild-d7bb91cd264300351e94e37a84b1de45f2312745.tar.gz attobuild-d7bb91cd264300351e94e37a84b1de45f2312745.tar.bz2 attobuild-d7bb91cd264300351e94e37a84b1de45f2312745.tar.xz attobuild-d7bb91cd264300351e94e37a84b1de45f2312745.zip |
Add a classy API, and use it to implement all the common options
Diffstat (limited to 'attoconf/lib/c.py')
-rw-r--r-- | attoconf/lib/c.py | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/attoconf/lib/c.py b/attoconf/lib/c.py new file mode 100644 index 0000000..4d3f252 --- /dev/null +++ b/attoconf/lib/c.py @@ -0,0 +1,268 @@ +# Copyright 2013 Ben Longbons <b.r.longbons@gmail.com> +# +# This file is part of attoconf. +# +# attoconf 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. +# +# attoconf 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 attoconf. If not, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function, division, absolute_import + +import errno +import os +from shlex import split as shell +import subprocess + +from .arches import Arches2 + +class TestError(Exception): + pass + +def do_exec(build, args): + p = subprocess.Popen(args, cwd=build.builddir, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + out, _ = p.communicate() + retcode = p.wait() + return retcode, out + + +class TempFile: + ''' context manager that optionally creates and then removes a file + ''' + __slots__ = ('filename') + + def __init__(self, filename, content): + self.filename = filename + if content is not None: + with open(filename, 'wx') as of: + of.write(content) + else: + # TODO: raise OSError(errno.EEXIST) if file already exists + pass + + def __enter__(self): + pass + + def __exit__(self, type, value, traceback): + try: + os.remove(self.filename) + except OSError as e: + if e.errno != errno.ENOENT: + raise + + +def try_compile_c(build, body, CFLAGS=[], CPPFLAGS=[]): + CC = build.vars['CC'][0] + CFLAGS = build.vars['CFLAGS'][0] + CFLAGS + CPPFLAGS = build.vars['CPPFLAGS'][0] + CPPFLAGS + in_ = 'atto-test.c' + ins = [in_] + out = 'atto-test.o' + + args = CC + CFLAGS + CPPFLAGS + ['-c', '-o', out, in_] + with TempFile(in_, body), TempFile(out, None): + status, error = do_exec(build, args) + if status: + raise TestError(error) + +def try_compile_link_c(build, body, CFLAGS=[], CPPFLAGS=[], LDFLAGS=[], LDLIBS=[]): + CC = build.vars['CC'][0] + CFLAGS = build.vars['CFLAGS'][0] + CFLAGS + CPPFLAGS = build.vars['CPPFLAGS'][0] + CPPFLAGS + LDFLAGS = build.vars['LDFLAGS'][0] + LDFLAGS + LDLIBS = build.vars['LDLIBS'][0] + LDLIBS + in_ = 'atto-test.c' + ins = [in_] + out = 'atto-test' + + args = CC + CFLAGS + CPPFLAGS + LDFLAGS + ins + LDLIBS + ['-o', out] + with TempFile(in_, body), TempFile(out, None): + status, error = do_exec(build, args) + if status: + raise TestError(error) + +def try_compile_cxx(build, body, CXXFLAGS=[], CPPFLAGS=[]): + CXX = build.vars['CXX'][0] + CXXFLAGS = build.vars['CXXFLAGS'][0] + CXXFLAGS + CPPFLAGS = build.vars['CPPFLAGS'][0] + CPPFLAGS + in_ = 'atto-test.cxx' + out = 'atto-test.o' + + args = CXX + CXXFLAGS + CPPFLAGS + ['-c', '-o', out, in_] + with TempFile(in_, body), TempFile(out, None): + status, error = do_exec(build, args) + if status: + raise TestError(error) + +def try_compile_link_cxx(build, body, CXXFLAGS=[], CPPFLAGS=[], LDFLAGS=[], LDLIBS=[]): + CXX = build.vars['CXX'][0] + CXXFLAGS = build.vars['CXXFLAGS'][0] + CXXFLAGS + CPPFLAGS = build.vars['CPPFLAGS'][0] + CPPFLAGS + LDFLAGS = build.vars['LDFLAGS'][0] + LDFLAGS + LDLIBS = build.vars['LDLIBS'][0] + LDLIBS + in_ = 'atto-test.cxx' + out = 'atto-test' + + args = CXX + CXXFLAGS + CPPFLAGS + LDFLAGS + ins + LDLIBS + ['-o', out] + with TempFile(in_, body), TempFile(out, None): + status, error = do_exec(build, args) + if status: + raise TestError(error) + +if 0: + def try_linkonly_c(build, ins, LDFLAGS=[], LDLIBS=[]): + CC = build.vars['CC'][0] + LDFLAGS = build.vars['LDFLAGS'][0] + LDFLAGS + LDLIBS = build.vars['LDLIBS'][0] + LDLIBS + out = 'atto-test' + + args = CC + LDFLAGS + ins + LDLIBS + ['-o', out] + with TempFile(out, None): + status, error = do_exec(build, args) + if status: + raise TestError(error) + +def try_compile_link2_c(build, body, CFLAGS=[], CPPFLAGS=[], LDFLAGS=[], LDLIBS=[]): + CC = build.vars['CC'][0] + CFLAGS = build.vars['CFLAGS'][0] + CFLAGS + CPPFLAGS = build.vars['CPPFLAGS'][0] + CPPFLAGS + LDFLAGS = build.vars['LDFLAGS'][0] + LDFLAGS + LDLIBS = build.vars['LDLIBS'][0] + LDLIBS + in_ = 'atto-test.c' + ins = [in_] + mid = 'atto-test.o' + mids = [mid] + out = 'atto-test' + + args1 = CC + CFLAGS + CPPFLAGS + ['-c', '-o', mid, in_] + args2 = CC + LDFLAGS + mids + LDLIBS + ['-o', out] + with TempFile(mid, None): + with TempFile(in_, body): + status, error = do_exec(build, args1) + if status: + raise TestError(error) + + with TempFile(out, None): + status, error = do_exec(build, args2) + if status: + raise TestError(error) + +if 0: + def try_linkonly_cxx(build, ins, LDFLAGS=[], LDLIBS=[]): + CXX = build.vars['CXX'][0] + LDFLAGS = build.vars['LDFLAGS'][0] + LDFLAGS + LDLIBS = build.vars['LDLIBS'][0] + LDLIBS + out = 'atto-test' + + args = CXX + LDFLAGS + ins + LDLIBS + ['-o', out] + with TempFile(out, None): + status, error = do_exec(build, args) + if status: + raise TestError(error) + +def try_compile_link2_cxx(build, body, CXXFLAGS=[], CPPFLAGS=[], LDFLAGS=[], LDLIBS=[]): + CXX = build.vars['CXX'][0] + CXXFLAGS = build.vars['CXXFLAGS'][0] + CXXFLAGS + CPPFLAGS = build.vars['CPPFLAGS'][0] + CPPFLAGS + LDFLAGS = build.vars['LDFLAGS'][0] + LDFLAGS + LDLIBS = build.vars['LDLIBS'][0] + LDLIBS + in_ = 'atto-test.cxx' + ins = [in_] + mid = 'atto-test.o' + mids = [mid] + out = 'atto-test' + + args1 = CXX + CXXFLAGS + CPPFLAGS + ['-c', '-o', mid, in_] + args2 = CXX + LDFLAGS + mids + LDLIBS + ['-o', out] + with TempFile(mid, None): + with TempFile(in_, body): + status, error = do_exec(build, args1) + if status: + raise TestError(error) + + with TempFile(out, None): + status, error = do_exec(build, args2) + if status: + raise TestError(error) + + +def ldflags(build, LDFLAGS): + pass + +def libs(build, LIBS): + # Make expects something different + build.vars['LDLIBS'] = build.vars['LIBS'] + del build.vars['LIBS'] + +def cppflags(build, CPPFLAGS): + pass + +def cc(build, CC): + pass + +def cflags(build, CFLAGS): + try_compile_c(build, 'int main() {}\n') + try_compile_link_c(build, 'int main() {}\n') + try_compile_link2_c(build, 'int main() {}\n') + +def cxx(build, CXX): + pass + +def cxxflags(build, CXXFLAGS): + try_compile_cxx(build, 'int main() {}\n') + try_compile_link_cxx(build, 'int main() {}\n') + try_compile_link2_cxx(build, 'int main() {}\n') + +class Link(Arches2): + __slots__ = () + def vars(self): + super(Link, self).vars() + self.add_option('LDFLAGS', init=[], + type=shell, check=ldflags, + help='linker flags, e.g. -L<lib dir> if you have libraries in a nonstandard directory <lib dir>', + hidden=False) + self.add_option('LIBS', init=[], + type=shell, check=libs, + help='libraries to pass to the linker, e.g. -l<library>', + hidden=False) + +class Preprocess(Arches2): + __slots__ = () + def vars(self): + super(Preprocess, self).vars() + self.add_option('CPPFLAGS', init=[], + type=shell, check=cppflags, + help='C/C++/Objective C preprocessor flags, e.g. -I<include dir> if you have headers in a nonstandard directory <include dir>', + hidden=False) + +class C(Link, Preprocess): + __slots__ = () + def vars(self): + super(C, self).vars() + self.add_option('CC', init=['gcc'], + type=shell, check=cc, + help='C compiler command', hidden=False) + self.add_option('CFLAGS', init=[], + type=shell, check=cflags, + help='C compiler flags', hidden=False) + +class Cxx(Link, Preprocess): + __slots__ = () + def vars(self): + super(Cxx, self).vars() + self.add_option('CXX', init=['g++'], + type=shell, check=cxx, + help='C++ compiler command', hidden=False) + self.add_option('CXXFLAGS', init=[], + type=shell, check=cxxflags, + help='C++ compiler flags', hidden=False) |