You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					117 lines
				
				5.3 KiB
			
		
		
			
		
	
	
					117 lines
				
				5.3 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								# -*- coding: future_fstrings -*-
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
							 | 
						||
| 
								 | 
							
								# Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
							 | 
						||
| 
								 | 
							
								# Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
							 | 
						||
| 
								 | 
							
								# Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# This file is part of acados.
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# The 2-Clause BSD License
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Redistribution and use in source and binary forms, with or without
							 | 
						||
| 
								 | 
							
								# modification, are permitted provided that the following conditions are met:
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# 1. Redistributions of source code must retain the above copyright notice,
							 | 
						||
| 
								 | 
							
								# this list of conditions and the following disclaimer.
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# 2. Redistributions in binary form must reproduce the above copyright notice,
							 | 
						||
| 
								 | 
							
								# this list of conditions and the following disclaimer in the documentation
							 | 
						||
| 
								 | 
							
								# and/or other materials provided with the distribution.
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
							 | 
						||
| 
								 | 
							
								# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
							 | 
						||
| 
								 | 
							
								# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
							 | 
						||
| 
								 | 
							
								# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
							 | 
						||
| 
								 | 
							
								# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
							 | 
						||
| 
								 | 
							
								# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
							 | 
						||
| 
								 | 
							
								# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
							 | 
						||
| 
								 | 
							
								# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
							 | 
						||
| 
								 | 
							
								# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
							 | 
						||
| 
								 | 
							
								# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
							 | 
						||
| 
								 | 
							
								# POSSIBILITY OF SUCH DAMAGE.;
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import sys
							 | 
						||
| 
								 | 
							
								from subprocess import call
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class CMakeBuilder:
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    Class to work with the `CMake` build system.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    def __init__(self):
							 | 
						||
| 
								 | 
							
								        self._source_dir = None  # private source directory, this is set to code_export_dir
							 | 
						||
| 
								 | 
							
								        self.build_dir = 'build'
							 | 
						||
| 
								 | 
							
								        self._build_dir = None  # private build directory, usually rendered to abspath(build_dir)
							 | 
						||
| 
								 | 
							
								        self.generator = None
							 | 
						||
| 
								 | 
							
								        """Defines the generator, options can be found via `cmake --help` under 'Generator'. Type: string. Linux default 'Unix Makefiles', Windows 'Visual Studio 15 2017 Win64'; default value: `None`."""
							 | 
						||
| 
								 | 
							
								        # set something for Windows
							 | 
						||
| 
								 | 
							
								        if os.name == 'nt':
							 | 
						||
| 
								 | 
							
								            self.generator = 'Visual Studio 15 2017 Win64'
							 | 
						||
| 
								 | 
							
								        self.build_targets = None
							 | 
						||
| 
								 | 
							
								        """A comma-separated list of the build targets, if `None` then all targets will be build; type: List of strings; default: `None`."""
							 | 
						||
| 
								 | 
							
								        self.options_on = None
							 | 
						||
| 
								 | 
							
								        """List of strings as CMake options which are translated to '-D Opt[0]=ON -D Opt[1]=ON ...'; default: `None`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Generate the command string for handling the cmake command.
							 | 
						||
| 
								 | 
							
								    def get_cmd1_cmake(self):
							 | 
						||
| 
								 | 
							
								        defines_str = ''
							 | 
						||
| 
								 | 
							
								        if self.options_on is not None:
							 | 
						||
| 
								 | 
							
								            defines_arr = [f' -D{opt}=ON' for opt in self.options_on]
							 | 
						||
| 
								 | 
							
								            defines_str = ' '.join(defines_arr)
							 | 
						||
| 
								 | 
							
								        generator_str = ''
							 | 
						||
| 
								 | 
							
								        if self.generator is not None:
							 | 
						||
| 
								 | 
							
								            generator_str = f' -G"{self.generator}"'
							 | 
						||
| 
								 | 
							
								        return f'cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="{self._source_dir}"{defines_str}{generator_str} -Wdev -S"{self._source_dir}" -B"{self._build_dir}"'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Generate the command string for handling the build.
							 | 
						||
| 
								 | 
							
								    def get_cmd2_build(self):
							 | 
						||
| 
								 | 
							
								        import multiprocessing
							 | 
						||
| 
								 | 
							
								        cmd = f'cmake --build "{self._build_dir}" --config Release -j{multiprocessing.cpu_count()}'
							 | 
						||
| 
								 | 
							
								        if self.build_targets is not None:
							 | 
						||
| 
								 | 
							
								            cmd += f' -t {self.build_targets}'
							 | 
						||
| 
								 | 
							
								        return cmd
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Generate the command string for handling the install command.
							 | 
						||
| 
								 | 
							
								    def get_cmd3_install(self):
							 | 
						||
| 
								 | 
							
								        return f'cmake --install "{self._build_dir}"'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def exec(self, code_export_directory):
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        Execute the compilation using `CMake` with the given settings.
							 | 
						||
| 
								 | 
							
								        :param code_export_directory: must be the absolute path to the directory where the code was exported to
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if(os.path.isabs(code_export_directory) is False):
							 | 
						||
| 
								 | 
							
								            print(f'(W) the code export directory "{code_export_directory}" is not an absolute path!')
							 | 
						||
| 
								 | 
							
								        self._source_dir = code_export_directory
							 | 
						||
| 
								 | 
							
								        self._build_dir = os.path.abspath(self.build_dir)
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            os.mkdir(self._build_dir)
							 | 
						||
| 
								 | 
							
								        except FileExistsError as e:
							 | 
						||
| 
								 | 
							
								            pass
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            os.chdir(self._build_dir)
							 | 
						||
| 
								 | 
							
								            cmd_str = self.get_cmd1_cmake()
							 | 
						||
| 
								 | 
							
								            print(f'call("{cmd_str})"')
							 | 
						||
| 
								 | 
							
								            retcode = call(cmd_str, shell=True)
							 | 
						||
| 
								 | 
							
								            if retcode != 0:
							 | 
						||
| 
								 | 
							
								                raise RuntimeError(f'CMake command "{cmd_str}" was terminated by signal {retcode}')
							 | 
						||
| 
								 | 
							
								            cmd_str = self.get_cmd2_build()
							 | 
						||
| 
								 | 
							
								            print(f'call("{cmd_str}")')
							 | 
						||
| 
								 | 
							
								            retcode = call(cmd_str, shell=True)
							 | 
						||
| 
								 | 
							
								            if retcode != 0:
							 | 
						||
| 
								 | 
							
								                raise RuntimeError(f'Build command "{cmd_str}" was terminated by signal {retcode}')
							 | 
						||
| 
								 | 
							
								            cmd_str = self.get_cmd3_install()
							 | 
						||
| 
								 | 
							
								            print(f'call("{cmd_str}")')
							 | 
						||
| 
								 | 
							
								            retcode = call(cmd_str, shell=True)
							 | 
						||
| 
								 | 
							
								            if retcode != 0:
							 | 
						||
| 
								 | 
							
								                raise RuntimeError(f'Install command "{cmd_str}" was terminated by signal {retcode}')
							 | 
						||
| 
								 | 
							
								        except OSError as e:
							 | 
						||
| 
								 | 
							
								            print("Execution failed:", e, file=sys.stderr)
							 | 
						||
| 
								 | 
							
								        except Exception as e:
							 | 
						||
| 
								 | 
							
								            print("Execution failed:", e, file=sys.stderr)
							 | 
						||
| 
								 | 
							
								            exit(1)
							 |