summaryrefslogtreecommitdiff
path: root/attoconf/lib/c.py
diff options
context:
space:
mode:
Diffstat (limited to 'attoconf/lib/c.py')
-rw-r--r--attoconf/lib/c.py281
1 files changed, 281 insertions, 0 deletions
diff --git a/attoconf/lib/c.py b/attoconf/lib/c.py
new file mode 100644
index 0000000..98d88df
--- /dev/null
+++ b/attoconf/lib/c.py
@@ -0,0 +1,281 @@
+# Copyright 2013-2014 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/>.
+
+
+
+import errno
+import os
+import subprocess
+
+from .arches import Arches2
+from ..types import ShellList
+
+class TestError(Exception):
+ pass
+
+def do_exec(build, args):
+ p = subprocess.Popen(args.list, 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, 'x') 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']
+ CFLAGS = build.vars['CFLAGS'] + CFLAGS
+ CPPFLAGS = build.vars['CPPFLAGS'] + 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=[], LIBS=[]):
+ CC = build.vars['CC']
+ CFLAGS = build.vars['CFLAGS'] + CFLAGS
+ CPPFLAGS = build.vars['CPPFLAGS'] + CPPFLAGS
+ LDFLAGS = build.vars['LDFLAGS'] + LDFLAGS
+ LIBS = build.vars['LIBS'] + LIBS
+ in_ = 'atto-test.c'
+ ins = [in_]
+ out = 'atto-test'
+
+ args = CC + CFLAGS + CPPFLAGS + LDFLAGS + ins + LIBS + ['-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']
+ CXXFLAGS = build.vars['CXXFLAGS'] + CXXFLAGS
+ CPPFLAGS = build.vars['CPPFLAGS'] + 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=[], LIBS=[]):
+ CXX = build.vars['CXX']
+ CXXFLAGS = build.vars['CXXFLAGS'] + CXXFLAGS
+ CPPFLAGS = build.vars['CPPFLAGS'] + CPPFLAGS
+ LDFLAGS = build.vars['LDFLAGS'] + LDFLAGS
+ LIBS = build.vars['LIBS'] + LIBS
+ in_ = 'atto-test.cxx'
+ ins = [in_]
+ out = 'atto-test'
+
+ args = CXX + CXXFLAGS + CPPFLAGS + LDFLAGS + ins + LIBS + ['-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=[], LIBS=[]):
+ CC = build.vars['CC']
+ LDFLAGS = build.vars['LDFLAGS'] + LDFLAGS
+ LIBS = build.vars['LIBS'] + LIBS
+ out = 'atto-test'
+
+ args = CC + LDFLAGS + ins + LIBS + ['-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=[], LIBS=[]):
+ CC = build.vars['CC']
+ CFLAGS = build.vars['CFLAGS'] + CFLAGS
+ CPPFLAGS = build.vars['CPPFLAGS'] + CPPFLAGS
+ LDFLAGS = build.vars['LDFLAGS'] + LDFLAGS
+ LIBS = build.vars['LIBS'] + LIBS
+ 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 + LIBS + ['-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=[], LIBS=[]):
+ CXX = build.vars['CXX']
+ LDFLAGS = build.vars['LDFLAGS'] + LDFLAGS
+ LIBS = build.vars['LIBS'] + LIBS
+ out = 'atto-test'
+
+ args = CXX + LDFLAGS + ins + LIBS + ['-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=[], LIBS=[]):
+ CXX = build.vars['CXX']
+ CXXFLAGS = build.vars['CXXFLAGS'] + CXXFLAGS
+ CPPFLAGS = build.vars['CPPFLAGS'] + CPPFLAGS
+ LDFLAGS = build.vars['LDFLAGS'] + LDFLAGS
+ LIBS = build.vars['LIBS'] + LIBS
+ 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 + LIBS + ['-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):
+ # compatibility
+ build.vars['LDLIBS'] = LIBS
+
+def cppflags(build, CPPFLAGS):
+ pass
+
+def cc(build, CC):
+ if CC.list == []:
+ HOST = build.vars['HOST']
+ if HOST:
+ build.vars['CC'].list = [HOST + '-gcc']
+ else:
+ build.vars['CC'].list = ['gcc']
+
+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):
+ if CXX.list == []:
+ HOST = build.vars['HOST']
+ if HOST:
+ build.vars['CXX'].list = [HOST + '-g++']
+ else:
+ build.vars['CXX'].list = ['g++']
+
+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=ShellList, 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=ShellList, check=libs,
+ help='libraries to pass to the linker, e.g. -l<library>',
+ hidden=False)
+ self.order.append('LDLIBS') #TODO remove for 1.0
+
+class Preprocess(Arches2):
+ __slots__ = ()
+ def vars(self):
+ super(Preprocess, self).vars()
+ self.add_option('CPPFLAGS', init=[],
+ type=ShellList, 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=[],
+ type=ShellList, check=cc,
+ help='C compiler command', hidden=False,
+ help_def='HOST-gcc')
+ self.add_option('CFLAGS', init=['-O2', '-g'],
+ type=ShellList, 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=[],
+ type=ShellList, check=cxx,
+ help='C++ compiler command', hidden=False,
+ help_def='HOST-g++')
+ self.add_option('CXXFLAGS', init=['-O2', '-g'],
+ type=ShellList, check=cxxflags,
+ help='C++ compiler flags', hidden=False)