1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3 4#------------------------------------------------------------------------------- 5 6# This file is part of Code_Saturne, a general-purpose CFD tool. 7# 8# Copyright (C) 1998-2021 EDF S.A. 9# 10# This program is free software; you can redistribute it and/or modify it under 11# the terms of the GNU General Public License as published by the Free Software 12# Foundation; either version 2 of the License, or (at your option) any later 13# version. 14# 15# This program is distributed in the hope that it will be useful, but WITHOUT 16# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18# details. 19# 20# You should have received a copy of the GNU General Public License along with 21# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin 22# Street, Fifth Floor, Boston, MA 02110-1301, USA. 23 24#------------------------------------------------------------------------------- 25 26import fnmatch 27import os 28import sys 29import tempfile 30 31from optparse import OptionParser 32 33from cs_exec_environment import separate_args 34from cs_compile import cs_compile 35 36#------------------------------------------------------------------------------- 37 38def process_cmd_line(argv): 39 """ 40 Processes the passed command line arguments for a build environment. 41 42 Input Argument: 43 arg -- This can be either a list of arguments as in 44 sys.argv[1:] or a string that is similar to the one 45 passed on the command line. If it is a string, 46 it is split to create a list of arguments. 47 """ 48 49 parser = OptionParser(usage="usage: %prog [options]") 50 51 parser.add_option("--mode", dest="mode", type="string", 52 metavar="<mode>", 53 help="'build' or 'install' mode") 54 55 parser.add_option("-d", "--dest", dest="dest_dir", type="string", 56 metavar="<dest_dir>", 57 help="choose executable file directory") 58 59 parser.add_option("-o", "--outfile", dest="out_file", type="string", 60 metavar="<out_file>", 61 help="choose executable file name") 62 63 parser.set_defaults(mode='build') 64 parser.set_defaults(dest_dir=None) 65 parser.set_defaults(out_file=None) 66 67 (options, args) = parser.parse_args(argv) 68 69 return options, args 70 71#------------------------------------------------------------------------------- 72 73def dest_subdir(destdir, d): 74 75 t = d 76 77 # Concatenate destdir and target subdirectory 78 79 if sys.platform.startswith("win"): 80 i = t.find(':\\') 81 if i > -1: 82 t = t[i+1:] 83 while t[0] == '\\': 84 t = t[1:] 85 else: 86 while t[0] == '/': 87 t = t[1:] 88 89 return os.path.join(destdir, t) 90 91#------------------------------------------------------------------------------- 92 93def src_include_dirs(srcdir): 94 """ 95 Return include directories in a given source directory. 96 """ 97 include_dirs = [] 98 99 if srcdir: 100 for f in os.listdir(os.path.join(srcdir, 'src')): 101 p = os.path.join(srcdir, 'src', f) 102 if os.path.isdir(p): 103 include_dirs.append(p) 104 105 return include_dirs 106 107#=============================================================================== 108# Class used to manage compilation in build directory 109#=============================================================================== 110 111class compile_build(cs_compile): 112 113 def __init__(self, 114 package=None, 115 srcdir=None): 116 """ 117 Initialize compiler object. 118 """ 119 cs_compile.__init__(self, package) 120 self.srcdir = srcdir 121 122 top_builddir = os.getcwd() 123 while not os.path.isfile(os.path.join(top_builddir, "cs_config.h")): 124 ds = os.path.split(top_builddir) 125 if ds[1]: 126 top_builddir = ds[0] 127 else: 128 break 129 130 if not os.path.isdir(os.path.join(top_builddir, "src")): 131 raise Exception("top build directory not detected from: " \ 132 + os.getcwd()) 133 134 self.top_builddir = top_builddir 135 136 #--------------------------------------------------------------------------- 137 138 def get_compiler(self, compiler): 139 """ 140 Determine the compiler path for a given compiler type. 141 """ 142 143 return self.pkg.config.compilers[compiler] 144 145 #--------------------------------------------------------------------------- 146 147 def flags_relocation(self, flag, cmd_line): 148 149 return 150 151 #--------------------------------------------------------------------------- 152 153 def get_pkg_path_flags(self, flag): 154 """ 155 Determine compilation flags for a given flag type. 156 """ 157 158 flags = [] 159 160 top_builddir = self.top_builddir 161 162 # Add CPPFLAGS and LDFLAGS information for the current package 163 if flag == 'cppflags': 164 if self.pkg.config.libs['ple'].variant == 'internal': 165 flags.append('-I' + os.path.join(top_builddir, 'libple')) 166 flags.append('-I' + os.path.join(self.srcdir, 'libple', 'src')) 167 flags.append('-I' + top_builddir) 168 include_dirs = src_include_dirs(self.srcdir) 169 for d in include_dirs: 170 flags.append('-I' + d) 171 172 elif flag == 'ldflags': 173 tsd = os.path.join(top_builddir, 'src') 174 for f in os.listdir(tsd): 175 p = os.path.join(tsd, f, '.libs') 176 if os.path.isdir(p): 177 flags.append('-L' + p) 178 if self.pkg.config.libs['ple'].variant == 'internal': 179 flags.append('-L' + os.path.join(top_builddir, 'libple', 180 'src', '.libs')) 181 l_cwd = '-L' + os.path.join(os.getcwd(), '.libs') 182 if not l_cwd in flags: 183 flags.append(l_cwd) 184 # Add library paths which may be indirectly required 185 re_lib_dirs = self.pkg.config.get_compile_dependency_paths() 186 for d in re_lib_dirs: 187 flags.insert(0, '-L' + d) 188 189 return flags 190 191 #--------------------------------------------------------------------------- 192 193 def get_ar_lib_dir(self): 194 """ 195 Determine directory containing library in archive mode. 196 """ 197 198 return os.path.join(self.top_builddir, "src", "apps", ".libs") 199 200#=============================================================================== 201# Class used to manage install 202#=============================================================================== 203 204class compile_install(cs_compile): 205 206 def __init__(self, 207 package=None, 208 srcdir=None, 209 destdir=None): 210 """ 211 Initialize compiler object. 212 """ 213 cs_compile.__init__(self, package) 214 self.srcdir = srcdir 215 216 self.destdir = destdir 217 218 #--------------------------------------------------------------------------- 219 220 def get_pkg_path_flags(self, flag): 221 """ 222 Determine compilation flags for a given flag type. 223 """ 224 225 flags = [] 226 227 # Add CPPFLAGS and LDFLAGS information for the current package 228 if flag == 'cppflags': 229 dirs = [] 230 dirs.insert(0, self.pkg.dirs['pkgincludedir']) 231 if self.pkg.config.libs['ple'].variant == "internal": 232 dirs.insert(0, self.pkg.dirs['includedir']) 233 for d in dirs: 234 if self.destdir: 235 flags.append("-I" + dest_subdir(self.destdir, d)) 236 else: 237 flags.append("-I" + d) 238 239 elif flag == 'ldflags': 240 # Do not use pkg.get_dir here as possible relocation paths must be 241 # used after installation, not before. 242 libdir = pkg.dirs['libdir'] 243 # Strangely, on MinGW, Windows paths are not correctly handled here 244 # So, assuming we always build on MinGW, here is a little trick! 245 if sys.platform.startswith("win"): 246 if pkg.get_cross_compile() != 'cygwin': # mingw64 247 libdir = os.path.normpath('C:\\MinGW\\msys\\1.0' + libdir) 248 if self.destdir: 249 libdir = dest_subdir(self.destdir, libdir) 250 flags.append("-L" + libdir) 251 252 return flags 253 254 #--------------------------------------------------------------------------- 255 256 def get_compiler(self, compiler): 257 """ 258 Determine the compiler path for a given compiler type. 259 """ 260 261 return self.pkg.config.compilers[compiler] 262 263 #--------------------------------------------------------------------------- 264 265 def flags_relocation(self, flag, cmd_line): 266 267 return 268 269 #--------------------------------------------------------------------------- 270 271 def get_flags(self, flag): 272 """ 273 Determine compilation flags for a given flag type. 274 """ 275 276 if flag == 'libs': 277 return cs_compile.get_flags(self, flag) 278 279 cmd_line = self.get_pkg_path_flags(flag) 280 281 # Build the command line, and split possible multiple arguments in lists. 282 for lib in pkg.config.deplibs: 283 if (pkg.config.libs[lib].have == True \ 284 and (not pkg.config.libs[lib].dynamic_load)): 285 cmd_line += separate_args(pkg.config.libs[lib].flags[flag]) 286 287 if flag == 'ldflags': 288 # Do not use pkg.get_dir here as possible relocation paths 289 # must be used after installation, not before. 290 libdir = pkg.dirs['libdir'] 291 # Strangely, on MinGW, Windows paths are not correctly 292 # handled here. So, assuming we always build on MinGW, 293 # here is a little trick! 294 if sys.platform.startswith("win"): 295 if pkg.get_cross_compile() != 'cygwin': # mingw64 296 libdir = os.path.normpath('C:\\MinGW\\msys\\1.0' + libdir) 297 if self.destdir: 298 libdir = dest_subdir(self.destdir, libdir) 299 cmd_line.insert(0, "-L" + libdir) 300 301 return cmd_line 302 303 #--------------------------------------------------------------------------- 304 305 def get_lib_dir(self): 306 """ 307 Determine directory containing library. 308 """ 309 310 cmd_line = self.get_pkg_path_flags(flag) 311 312 # Build the command line, and split possible multiple arguments in lists. 313 for lib in pkg.config.deplibs: 314 if (pkg.config.libs[lib].have == True \ 315 and (not pkg.config.libs[lib].dynamic_load)): 316 cmd_line += separate_args(pkg.config.libs[lib].flags[flag]) 317 318 print(cmd_line) 319 print(self.pkg.config.rpath) 320 321#=============================================================================== 322# Functions 323#=============================================================================== 324 325def install_exec_name(pkg, exec_name, destdir=None): 326 """ 327 Determine full executable path and create associated directory 328 if necessary 329 """ 330 331 exec_name = os.path.join(pkg.dirs['pkglibexecdir'], exec_name) 332 # Strangely, on MinGW, Windows paths are not correctly handled here... 333 # So, assuming we always build on MinGW, here is a little trick! 334 if sys.platform.startswith("win"): 335 if pkg.get_cross_compile() != 'cygwin': # mingw64 336 exec_name = os.path.normpath('C:\\MinGW\\msys\\1.0' + exec_name) 337 else: 338 exec_name = os.path.join(pkg.dirs['pkglibexecdir'], 339 os.path.basename(exec_name)) 340 if destdir: 341 exec_name = dest_subdir(destdir, exec_name) 342 dirname = os.path.dirname(exec_name) 343 if not os.path.exists(dirname): 344 os.makedirs(dirname) 345 346 return exec_name 347 348#------------------------------------------------------------------------------- 349 350if __name__ == '__main__': 351 352 # Check mode and options 353 options, src_files = process_cmd_line(sys.argv[1:]) 354 355 top_builddir = os.getenv("CS_TOP_BUILDDIR") 356 config_file_base = os.path.join("lib", "code_saturne_build.cfg") 357 358 if top_builddir: 359 top_builddir = os.path.abspath(top_builddir) 360 config_file = os.path.join(top_builddir, config_file_base) 361 else: 362 top_builddir = os.path.abspath(os.getcwd()) 363 t = os.path.split(top_builddir) 364 while (t[1]): 365 config_file = os.path.join(top_builddir, config_file_base) 366 if os.path.isfile(config_file): 367 break; 368 t = os.path.split(top_builddir) 369 top_builddir = os.path.abspath(t[0]) 370 371 # Retrieve package information (name, version, installation dirs, ...) 372 373 from cs_package import package 374 375 pkg = package(config_file=config_file, install_mode=True) 376 377 src_dir = None 378 if src_files: 379 src_dir = os.path.dirname(os.path.dirname(sys.argv[0])) 380 381 # Determine executable name 382 383 exec_name=options.out_file 384 if not exec_name: 385 exec_name = 'cs_solver' 386 if os.path.basename(sys.argv[0]) == 'neptune_cfd': 387 exec_name = 'nc_solver' 388 389 if options.mode == 'install': 390 c = compile_install(pkg, src_dir, destdir=options.dest_dir) 391 exec_name = install_exec_name(pkg, exec_name, options.dest_dir) 392 else: 393 c = compile_build(pkg, src_dir) 394 395 retcode = 0 396 o_files = None 397 if src_files: 398 retcode, o_files = c.compile_src(src_list=src_files) 399 400 if retcode == 0: 401 print("Linking executable: " + exec_name) 402 retcode = c.link_obj(exec_name, o_files) 403 404 sys.exit(retcode) 405 406#------------------------------------------------------------------------------- 407# End 408#------------------------------------------------------------------------------- 409