Merge branch 'master' into yaml

This commit is contained in:
Radovan Bast 2016-04-10 17:26:02 +02:00
commit 69478cb27e
5 changed files with 63 additions and 65 deletions

View File

@ -1,5 +1,4 @@
[![Build Status](https://travis-ci.org/scisoft/autocmake.svg?branch=master)](https://travis-ci.org/scisoft/autocmake/builds) [![Build Status](https://travis-ci.org/scisoft/autocmake.svg?branch=master)](https://travis-ci.org/scisoft/autocmake/builds)
[![Build Status](https://ci.appveyor.com/api/projects/status/github/scisoft/autocmake?branch=master&svg=true)](https://ci.appveyor.com/project/bast/autocmake/history)
[![Documentation Status](https://readthedocs.org/projects/autocmake/badge/?version=latest)](http://autocmake.readthedocs.org) [![Documentation Status](https://readthedocs.org/projects/autocmake/badge/?version=latest)](http://autocmake.readthedocs.org)
[![License](https://img.shields.io/badge/license-%20BSD--3-blue.svg)](../master/LICENSE) [![License](https://img.shields.io/badge/license-%20BSD--3-blue.svg)](../master/LICENSE)

View File

@ -21,6 +21,3 @@ For more options, see the ``py.test`` flags.
This test set is run upon each push to the central repository. This test set is run upon each push to the central repository.
See also the `Travis <https://travis-ci.org/scisoft/autocmake/builds>`__ See also the `Travis <https://travis-ci.org/scisoft/autocmake/builds>`__
build and test history. build and test history.
In addition we also test Autocmake on a Windows CI server: `Appveyor <https://ci.appveyor.com/project/bast/autocmake/history>`__.
This is controlled by `Appveyor <https://github.com/scisoft/autocmake/blob/master/appveyor.yml>`__.

View File

@ -47,4 +47,8 @@ How can I select CMake options via the setup script?
Like this:: Like this::
$ python setup --cmake-options="-DTHIS_OPTION=ON -DTHAT_OPTION=OFF" $ python setup --cmake-options='"-DTHIS_OPTION=ON -DTHAT_OPTION=OFF"'
We use two sets of quotes because the shell swallows one set of them
before passing the arguments to Python. If you do not use two sets
of quotes then the setup command may end up incorrectly saved in `build/setup_command`.

View File

@ -3,10 +3,8 @@
# See https://github.com/scisoft/autocmake/blob/master/LICENSE # See https://github.com/scisoft/autocmake/blob/master/LICENSE
import subprocess
import os import os
import sys import sys
import shutil
def module_exists(module_name): def module_exists(module_name):
@ -23,10 +21,12 @@ def check_cmake_exists(cmake_command):
Check whether CMake is installed. If not, print Check whether CMake is installed. If not, print
informative error message and quits. informative error message and quits.
""" """
p = subprocess.Popen('%s --version' % cmake_command, from subprocess import Popen, PIPE
shell=True,
stdin=subprocess.PIPE, p = Popen('{} --version'.format(cmake_command),
stdout=subprocess.PIPE) shell=True,
stdin=PIPE,
stdout=PIPE)
if not ('cmake version' in p.communicate()[0].decode('UTF-8')): if not ('cmake version' in p.communicate()[0].decode('UTF-8')):
sys.stderr.write(' This code is built using CMake\n\n') sys.stderr.write(' This code is built using CMake\n\n')
sys.stderr.write(' CMake is not found\n') sys.stderr.write(' CMake is not found\n')
@ -46,7 +46,7 @@ def setup_build_path(build_path):
fname = os.path.join(build_path, 'CMakeCache.txt') fname = os.path.join(build_path, 'CMakeCache.txt')
if os.path.exists(fname): if os.path.exists(fname):
sys.stderr.write('aborting setup\n') sys.stderr.write('aborting setup\n')
sys.stderr.write('build directory %s which contains CMakeCache.txt already exists\n' % build_path) sys.stderr.write('build directory {} which contains CMakeCache.txt already exists\n'.format(build_path))
sys.stderr.write('remove the build directory and then rerun setup\n') sys.stderr.write('remove the build directory and then rerun setup\n')
sys.exit(1) sys.exit(1)
else: else:
@ -74,7 +74,7 @@ def adapt_cmake_command_to_platform(cmake_command, platform):
""" """
if platform == 'win32': if platform == 'win32':
pos = cmake_command.find('cmake') pos = cmake_command.find('cmake')
s = ['set %s &&' % e for e in cmake_command[:pos].split()] s = ['set {} &&'.format(e) for e in cmake_command[:pos].split()]
s.append(cmake_command[pos:]) s.append(cmake_command[pos:])
return ' '.join(s) return ' '.join(s)
else: else:
@ -85,13 +85,16 @@ def run_cmake(command, build_path, default_build_path):
""" """
Execute CMake command. Execute CMake command.
""" """
from subprocess import Popen, PIPE
from shutil import rmtree
topdir = os.getcwd() topdir = os.getcwd()
os.chdir(build_path) os.chdir(build_path)
p = subprocess.Popen(command, p = Popen(command,
shell=True, shell=True,
stdin=subprocess.PIPE, stdin=PIPE,
stdout=subprocess.PIPE, stdout=PIPE,
stderr=subprocess.PIPE) stderr=PIPE)
stdout_coded, stderr_coded = p.communicate() stdout_coded, stderr_coded = p.communicate()
stdout = stdout_coded.decode('UTF-8') stdout = stdout_coded.decode('UTF-8')
stderr = stderr_coded.decode('UTF-8') stderr = stderr_coded.decode('UTF-8')
@ -101,9 +104,8 @@ def run_cmake(command, build_path, default_build_path):
# print cmake output to screen # print cmake output to screen
print(stdout) print(stdout)
# write cmake output to file # write cmake output to file
f = open('cmake_output', 'w') with open('cmake_output', 'w') as f:
f.write(stdout) f.write(stdout)
f.close()
# change directory and return # change directory and return
os.chdir(topdir) os.chdir(topdir)
if 'Configuring incomplete' in stdout: if 'Configuring incomplete' in stdout:
@ -111,7 +113,7 @@ def run_cmake(command, build_path, default_build_path):
if (build_path == default_build_path): if (build_path == default_build_path):
# remove build_path iff not set by the user # remove build_path iff not set by the user
# otherwise removal can be dangerous # otherwise removal can be dangerous
shutil.rmtree(default_build_path) rmtree(default_build_path)
else: else:
# configuration was successful # configuration was successful
save_setup_command(sys.argv, build_path) save_setup_command(sys.argv, build_path)
@ -136,9 +138,8 @@ def save_setup_command(argv, build_path):
Save setup command to a file. Save setup command to a file.
""" """
file_name = os.path.join(build_path, 'setup_command') file_name = os.path.join(build_path, 'setup_command')
f = open(file_name, 'w') with open(file_name, 'w') as f:
f.write(' '.join(argv[:]) + '\n') f.write(' '.join(argv[:]) + '\n')
f.close()
def configure(root_directory, build_path, cmake_command, only_show): def configure(root_directory, build_path, cmake_command, only_show):
@ -158,7 +159,7 @@ def configure(root_directory, build_path, cmake_command, only_show):
cmake_command = adapt_cmake_command_to_platform(cmake_command, sys.platform) cmake_command = adapt_cmake_command_to_platform(cmake_command, sys.platform)
print('%s\n' % cmake_command) print('{}\n'.format(cmake_command))
if only_show: if only_show:
sys.exit(0) sys.exit(0)

View File

@ -14,7 +14,7 @@ if sys.version_info[0] > 2:
class URLopener(urllib.request.FancyURLopener): class URLopener(urllib.request.FancyURLopener):
def http_error_default(self, url, fp, errcode, errmsg, headers): def http_error_default(self, url, fp, errcode, errmsg, headers):
sys.stderr.write("ERROR: could not fetch %s\n" % url) sys.stderr.write("ERROR: could not fetch {}\n".format(url))
sys.exit(-1) sys.exit(-1)
else: else:
from StringIO import StringIO from StringIO import StringIO
@ -22,7 +22,7 @@ else:
class URLopener(urllib.FancyURLopener): class URLopener(urllib.FancyURLopener):
def http_error_default(self, url, fp, errcode, errmsg, headers): def http_error_default(self, url, fp, errcode, errmsg, headers):
sys.stderr.write("ERROR: could not fetch %s\n" % url) sys.stderr.write("ERROR: could not fetch {}\n".format(url))
sys.exit(-1) sys.exit(-1)
@ -119,7 +119,7 @@ def print_progress_bar(text, done, total, width):
Print progress bar. Print progress bar.
""" """
n = int(float(width) * float(done) / float(total)) n = int(float(width) * float(done) / float(total))
sys.stdout.write("\r%s [%s%s] (%i/%i)" % (text, '#' * n, sys.stdout.write("\r{0} [{1}{2}] ({3}/{4})".format(text, '#' * n,
' ' * (width - n), done, total)) ' ' * (width - n), done, total))
sys.stdout.flush() sys.stdout.flush()
@ -136,7 +136,7 @@ def align_options(options):
l = len(opt[0]) l = len(opt[0])
s = [] s = []
for opt in options: for opt in options:
s.append(' %s%s %s' % (opt[0], ' ' * (l - len(opt[0])), opt[1])) s.append(' {0}{1} {2}'.format(opt[0], ' ' * (l - len(opt[0])), opt[1]))
return '\n'.join(s) return '\n'.join(s)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -158,20 +158,20 @@ def gen_cmake_command(config):
for section in config.sections(): for section in config.sections():
if config.has_option(section, 'export'): if config.has_option(section, 'export'):
for env in config.get(section, 'export').split('\n'): for env in config.get(section, 'export').split('\n'):
s.append(' command.append(%s)' % env) s.append(' command.append({})'.format(env))
s.append(" command.append('%s' % arguments['--cmake-executable'])") s.append(" command.append(arguments['--cmake-executable'])")
# take care of cmake definitions # take care of cmake definitions
for section in config.sections(): for section in config.sections():
if config.has_option(section, 'define'): if config.has_option(section, 'define'):
for definition in config.get(section, 'define').split('\n'): for definition in config.get(section, 'define').split('\n'):
s.append(' command.append(%s)' % definition) s.append(' command.append({})'.format(definition))
s.append(" command.append('-DCMAKE_BUILD_TYPE=%s' % arguments['--type'])") s.append(" command.append('-DCMAKE_BUILD_TYPE={}'.format(arguments['--type']))")
s.append(" command.append('-G \"%s\"' % arguments['--generator'])") s.append(" command.append('-G \"{}\"'.format(arguments['--generator']))")
s.append(" if arguments['--cmake-options'] != \"''\":") s.append(" if arguments['--cmake-options'] != \"''\":")
s.append(" command.append('%s' % arguments['--cmake-options'])") s.append(" command.append(arguments['--cmake-options'])")
s.append(" if arguments['--prefix']:") s.append(" if arguments['--prefix']:")
s.append(" command.append('-DCMAKE_INSTALL_PREFIX=\"{0}\"'.format(arguments['--prefix']))") s.append(" command.append('-DCMAKE_INSTALL_PREFIX=\"{0}\"'.format(arguments['--prefix']))")
@ -183,14 +183,11 @@ def gen_cmake_command(config):
def autogenerated_notice(): def autogenerated_notice():
start_year = 2015
year_range = str(start_year)
current_year = datetime.date.today().year current_year = datetime.date.today().year
if current_year > start_year: year_range = '2015-{}'.format(current_year)
year_range += '-%s' % current_year
s = [] s = []
s.append('# This file is autogenerated by Autocmake http://autocmake.org') s.append('# This file is autogenerated by Autocmake http://autocmake.org')
s.append('# Copyright (c) %s by Radovan Bast and Jonas Juselius' % year_range) s.append('# Copyright (c) {} by Radovan Bast and Jonas Juselius'.format(year_range))
return '\n'.join(s) return '\n'.join(s)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -202,7 +199,7 @@ def gen_setup(config, relative_path, setup_script_name):
""" """
s = [] s = []
s.append('#!/usr/bin/env python') s.append('#!/usr/bin/env python')
s.append('\n%s' % autogenerated_notice()) s.append('\n{}'.format(autogenerated_notice()))
s.append('\nimport os') s.append('\nimport os')
s.append('import sys') s.append('import sys')
@ -247,7 +244,7 @@ def gen_setup(config, relative_path, setup_script_name):
s.append("try:") s.append("try:")
s.append(" arguments = docopt.docopt(options, argv=None)") s.append(" arguments = docopt.docopt(options, argv=None)")
s.append("except docopt.DocoptExit:") s.append("except docopt.DocoptExit:")
s.append(r" sys.stderr.write('ERROR: bad input to %s\n' % sys.argv[0])") s.append(r" sys.stderr.write('ERROR: bad input to {}\n'.format(sys.argv[0]))")
s.append(" sys.stderr.write(options)") s.append(" sys.stderr.write(options)")
s.append(" sys.exit(-1)") s.append(" sys.exit(-1)")
s.append("\n") s.append("\n")
@ -261,7 +258,7 @@ def gen_setup(config, relative_path, setup_script_name):
s.append("build_path = arguments['<builddir>']") s.append("build_path = arguments['<builddir>']")
s.append("\n") s.append("\n")
s.append("# create cmake command") s.append("# create cmake command")
s.append("cmake_command = '%s %s' % (gen_cmake_command(options, arguments), root_directory)") s.append("cmake_command = '{0} {1}'.format(gen_cmake_command(options, arguments), root_directory)")
s.append("\n") s.append("\n")
s.append("# run cmake") s.append("# run cmake")
s.append("config.configure(root_directory, build_path, cmake_command, arguments['--show'])") s.append("config.configure(root_directory, build_path, cmake_command, arguments['--show'])")
@ -280,10 +277,10 @@ def gen_cmakelists(project_name, min_cmake_version, relative_path, modules):
s.append(autogenerated_notice()) s.append(autogenerated_notice())
s.append('\n# set minimum cmake version') s.append('\n# set minimum cmake version')
s.append('cmake_minimum_required(VERSION %s FATAL_ERROR)' % min_cmake_version) s.append('cmake_minimum_required(VERSION {} FATAL_ERROR)'.format(min_cmake_version))
s.append('\n# project name') s.append('\n# project name')
s.append('project(%s)' % project_name) s.append('project({})'.format(project_name))
s.append('\n# do not rebuild if rules (compiler flags) change') s.append('\n# do not rebuild if rules (compiler flags) change')
s.append('set(CMAKE_SKIP_RULE_DEPENDENCY TRUE)') s.append('set(CMAKE_SKIP_RULE_DEPENDENCY TRUE)')
@ -304,12 +301,12 @@ def gen_cmakelists(project_name, min_cmake_version, relative_path, modules):
rel_cmake_module_path = os.path.join(relative_path, directory) rel_cmake_module_path = os.path.join(relative_path, directory)
# on windows cmake corrects this so we have to make it wrong again # on windows cmake corrects this so we have to make it wrong again
rel_cmake_module_path = rel_cmake_module_path.replace('\\', '/') rel_cmake_module_path = rel_cmake_module_path.replace('\\', '/')
s.append('set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/%s)' % rel_cmake_module_path) s.append('set(CMAKE_MODULE_PATH ${{CMAKE_MODULE_PATH}} ${{PROJECT_SOURCE_DIR}}/{})'.format(rel_cmake_module_path))
if len(modules) > 0: if len(modules) > 0:
s.append('\n# included cmake modules') s.append('\n# included cmake modules')
for module in modules: for module in modules:
s.append('include(%s)' % os.path.splitext(module.name)[0]) s.append('include({})'.format(os.path.splitext(module.name)[0]))
return s return s
@ -324,7 +321,7 @@ def prepend_or_set(config, section, option, value, defaults):
""" """
if value: if value:
if config.has_option(section, option): if config.has_option(section, option):
value += '\n%s' % config.get(section, option, 0, defaults) value += '\n{}'.format(config.get(section, option, 0, defaults))
config.set(section, option, value) config.set(section, option, value)
return config return config
@ -359,8 +356,8 @@ def fetch_modules(config, relative_path):
module_name = os.path.basename(src) module_name = os.path.basename(src)
if 'http' in src: if 'http' in src:
path = download_directory path = download_directory
name = 'autocmake_%s' % module_name name = 'autocmake_{}'.format(module_name)
dst = os.path.join(download_directory, 'autocmake_%s' % module_name) dst = os.path.join(download_directory, 'autocmake_{}'.format(module_name))
fetch_url(src, dst) fetch_url(src, dst)
file_name = dst file_name = dst
fetch_dst_directory = download_directory fetch_dst_directory = download_directory
@ -371,7 +368,7 @@ def fetch_modules(config, relative_path):
file_name = src file_name = src
fetch_dst_directory = path fetch_dst_directory = path
else: else:
sys.stderr.write("ERROR: %s does not exist\n" % src) sys.stderr.write("ERROR: {} does not exist\n".format(src))
sys.exit(-1) sys.exit(-1)
if config.has_option(section, 'override'): if config.has_option(section, 'override'):
@ -409,7 +406,7 @@ def fetch_modules(config, relative_path):
print('') print('')
if warnings != []: if warnings != []:
print('- %s' % '\n- '.join(warnings)) print('- {}'.format('\n- '.join(warnings)))
return modules return modules
@ -424,11 +421,11 @@ def main(argv):
sys.stderr.write("\nYou can update a project in two steps.\n\n") sys.stderr.write("\nYou can update a project in two steps.\n\n")
sys.stderr.write("Step 1: Update or create infrastructure files\n") sys.stderr.write("Step 1: Update or create infrastructure files\n")
sys.stderr.write(" which will be needed to configure and build the project:\n") sys.stderr.write(" which will be needed to configure and build the project:\n")
sys.stderr.write(" $ %s --self\n\n" % argv[0]) sys.stderr.write(" $ {} --self\n\n".format(argv[0]))
sys.stderr.write("Step 2: Create CMakeLists.txt and setup script in PROJECT_ROOT:\n") sys.stderr.write("Step 2: Create CMakeLists.txt and setup script in PROJECT_ROOT:\n")
sys.stderr.write(" $ %s <PROJECT_ROOT>\n" % argv[0]) sys.stderr.write(" $ {} <PROJECT_ROOT>\n".format(argv[0]))
sys.stderr.write(" example:\n") sys.stderr.write(" example:\n")
sys.stderr.write(" $ %s ..\n" % argv[0]) sys.stderr.write(" $ {} ..\n".format(argv[0]))
sys.exit(-1) sys.exit(-1)
if argv[1] in ['-h', '--help']: if argv[1] in ['-h', '--help']:
@ -443,7 +440,7 @@ def main(argv):
if not os.path.isfile('autocmake.yml'): if not os.path.isfile('autocmake.yml'):
print('- fetching example autocmake.yml') # FIXME print('- fetching example autocmake.yml') # FIXME
fetch_url( fetch_url(
src='%s/raw/master/example/autocmake.yml' % AUTOCMAKE_GITHUB_URL, src='{}/raw/master/example/autocmake.yml'.format(AUTOCMAKE_GITHUB_URL),
dst='autocmake.yml' dst='autocmake.yml'
) )
if not os.path.isfile('.gitignore'): if not os.path.isfile('.gitignore'):
@ -452,24 +449,24 @@ def main(argv):
f.write('*.pyc\n') f.write('*.pyc\n')
print('- fetching lib/config.py') print('- fetching lib/config.py')
fetch_url( fetch_url(
src='%s/raw/master/lib/config.py' % AUTOCMAKE_GITHUB_URL, src='{}/raw/master/lib/config.py'.format(AUTOCMAKE_GITHUB_URL),
dst='lib/config.py' dst='lib/config.py'
) )
print('- fetching lib/docopt/docopt.py') print('- fetching lib/docopt/docopt.py')
fetch_url( fetch_url(
src='%s/raw/master/lib/docopt/docopt.py' % AUTOCMAKE_GITHUB_URL, src='{}/raw/master/lib/docopt/docopt.py'.format(AUTOCMAKE_GITHUB_URL),
dst='lib/docopt/docopt.py' dst='lib/docopt/docopt.py'
) )
print('- fetching update.py') print('- fetching update.py')
fetch_url( fetch_url(
src='%s/raw/master/update.py' % AUTOCMAKE_GITHUB_URL, src='{}/raw/master/update.py'.format(AUTOCMAKE_GITHUB_URL),
dst='update.py' dst='update.py'
) )
sys.exit(0) sys.exit(0)
project_root = argv[1] project_root = argv[1]
if not os.path.isdir(project_root): if not os.path.isdir(project_root):
sys.stderr.write("ERROR: %s is not a directory\n" % project_root) sys.stderr.write("ERROR: {} is not a directory\n".format(project_root))
sys.exit(-1) sys.exit(-1)
# read config file # read config file
@ -506,14 +503,14 @@ def main(argv):
print('- generating CMakeLists.txt') print('- generating CMakeLists.txt')
s = gen_cmakelists(project_name, min_cmake_version, relative_path, modules) s = gen_cmakelists(project_name, min_cmake_version, relative_path, modules)
with open(os.path.join(project_root, 'CMakeLists.txt'), 'w') as f: with open(os.path.join(project_root, 'CMakeLists.txt'), 'w') as f:
f.write('%s\n' % '\n'.join(s)) f.write('{}\n'.format('\n'.join(s)))
# create setup script # create setup script
print('- generating setup script') print('- generating setup script')
s = gen_setup(config, relative_path, setup_script_name) s = gen_setup(config, relative_path, setup_script_name)
file_path = os.path.join(project_root, setup_script_name) file_path = os.path.join(project_root, setup_script_name)
with open(file_path, 'w') as f: with open(file_path, 'w') as f:
f.write('%s\n' % '\n'.join(s)) f.write('{}\n'.format('\n'.join(s)))
if sys.platform != 'win32': if sys.platform != 'win32':
make_executable(file_path) make_executable(file_path)
@ -581,8 +578,8 @@ def test_parse_cmake_module():
# #
# docopt: --cxx=<CXX> C++ compiler [default: g++]. # docopt: --cxx=<CXX> C++ compiler [default: g++].
# --extra-cxx-flags=<EXTRA_CXXFLAGS> Extra C++ compiler flags [default: '']. # --extra-cxx-flags=<EXTRA_CXXFLAGS> Extra C++ compiler flags [default: ''].
# export: 'CXX=%s' % arguments['--cxx'] # export: 'CXX={}'.format(arguments['--cxx'])
# define: '-DEXTRA_CXXFLAGS="%s"' % arguments['--extra-cxx-flags'] # define: '-DEXTRA_CXXFLAGS="{}"'.format(arguments['--extra-cxx-flags'])
enable_language(CXX) enable_language(CXX)