irpf90/src/ninja.py

422 lines
13 KiB
Python
Raw Permalink Normal View History

2020-01-27 18:22:35 +01:00
#!/usr/bin/env python3
2015-05-28 00:28:17 +02:00
# IRPF90 is a Fortran90 preprocessor written in Python for programming using
# the Implicit Reference to Parameters (IRP) method.
2020-12-06 20:48:35 +01:00
# Copyright (C) 2009 Anthony SCEMAMA
2015-05-28 00:28:17 +02:00
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Anthony Scemama
# LCPQ - IRSAMC - CNRS
# Universite Paul Sabatier
2020-12-06 20:48:35 +01:00
# 118, route de Narbonne
# 31062 Toulouse Cedex 4
2015-05-28 00:28:17 +02:00
# scemama@irsamc.ups-tlse.fr
import os,sys
2020-03-17 10:36:08 +01:00
import irpf90_t
2020-01-27 18:43:22 +01:00
from command_line import command_line
from modules import modules
2015-05-28 00:28:17 +02:00
irpdir = irpf90_t.irpdir
mandir = irpf90_t.mandir
2015-06-01 14:21:41 +02:00
irp_id = irpf90_t.irp_id
2015-05-28 00:28:17 +02:00
2015-06-10 12:10:14 +02:00
FILENAME = os.path.join(irpdir,"build.ninja")
2015-05-28 00:28:17 +02:00
cwd = os.getcwd()
2015-06-01 14:21:41 +02:00
PRINT_WIDTH=50
2020-12-06 20:48:35 +01:00
if sys.platform in ["linux", "linux2"]:
AR = "ar crs"
elif sys.platform == "darwin":
AR = "libtool -static -o"
else:
print("Unknown platform. Only Linux and Darwin are supported.")
sys.exit(-1)
2015-05-28 00:28:17 +02:00
def dress(f,in_root=False):
"""
Transfoms the filename f into $PWD/IRPF90_temp/f
"""
if in_root:
result = os.path.join(cwd,f)
else:
result = os.path.join(cwd,irpdir,f)
2021-05-19 18:36:43 +02:00
result = os.path.normpath(result)
return result
2015-05-28 00:28:17 +02:00
def create_build_touches(list_of_other_o):
"""
2015-06-01 14:33:24 +02:00
Create the build command for the irp_touches.o file and the irpf90.a library.
2015-05-28 00:28:17 +02:00
"""
name = "irp_touches"
2015-06-01 14:33:24 +02:00
short_lib = "irpf90.a"
2015-06-01 14:21:41 +02:00
short_target_o = "%s.irp.o"%name
short_target_F90 = "%s.irp.F90"%name
2015-06-01 14:33:24 +02:00
lib = dress(short_lib)
2015-06-01 14:21:41 +02:00
target_o = dress(short_target_o)
target_F90 = dress(short_target_F90)
2015-05-28 00:28:17 +02:00
needed_modules = [ "%s.irp.module.o"%(modules[x].filename) for x in modules ]
2020-01-27 18:22:35 +01:00
list_of_modules = list(map(dress, needed_modules)) + list_of_other_o
2015-05-28 00:28:17 +02:00
list_of_modules = ' '.join(list_of_modules)
2015-06-01 14:21:41 +02:00
result = '\n'.join(
2020-12-06 20:48:35 +01:00
[
2015-06-01 14:21:41 +02:00
"build {target_o}: compile_touches_{id} {target_F90} | {list_of_modules}",
" short_in = {short_target_F90}",
" short_out = {short_target_o}",
"",
2015-06-01 14:33:24 +02:00
"build {lib}: link_lib_{id} {target_o} {list_of_modules}",
" short_out = {short_lib}",
"",
2015-05-28 00:28:17 +02:00
] )
result = result.format(
2015-06-01 14:21:41 +02:00
id = irp_id ,
2015-06-01 14:33:24 +02:00
lib = lib ,
2015-06-01 14:21:41 +02:00
list_of_modules = list_of_modules ,
2015-06-01 14:33:24 +02:00
short_lib = short_lib ,
short_target_F90 = os.path.split(target_F90)[1] ,
short_target_o = os.path.split(target_o)[1] ,
2015-05-28 00:28:17 +02:00
target_F90 = target_F90 ,
2020-12-06 20:48:35 +01:00
target_o = target_o
2015-05-28 00:28:17 +02:00
)
return result
def create_build_target(t,list_of_other_o):
"""
Create the build command for the target module t. t is a Fmodule object.
"""
name = t.filename
2015-06-01 14:33:24 +02:00
irp_lib = dress("irpf90.a")
2015-05-28 00:28:17 +02:00
target = dress(name,in_root=True)
2015-06-01 14:21:41 +02:00
short_target_o = "%s.irp.o"%name
short_target_F90 = "%s.irp.F90"%name
short_target_module_F90 = "%s.irp.module.F90"%name
short_target_module_o = "%s.irp.module.o"%name
target_o = dress(short_target_o)
target_F90 = dress(short_target_F90)
target_module_o = dress(short_target_module_o)
target_module_F90 = dress(short_target_module_F90)
2015-05-28 00:28:17 +02:00
needed_modules = [ "%s.irp.module.o"%(modules[x].filename) for x in modules \
if modules[x].name in t.needed_modules ] + [ target_module_o ]
2020-12-06 20:48:35 +01:00
list_of_o = [ target_o, target_module_o, irp_lib ]
2015-05-28 00:28:17 +02:00
list_of_o = ' '.join(list_of_o)
2020-01-27 18:22:35 +01:00
list_of_modules = list(map(dress, needed_modules)) + list_of_other_o
2015-05-28 00:28:17 +02:00
list_of_modules = ' '.join(list_of_modules)
2020-01-27 18:22:35 +01:00
list_of_includes = ' '.join([dress(x,in_root=True) for x in t.includes])
2015-05-28 00:28:17 +02:00
2015-06-01 14:21:41 +02:00
result = '\n'.join(
2020-12-06 20:48:35 +01:00
[ "build {target}: link_{id} {list_of_o}",
2015-06-01 14:21:41 +02:00
" short_out = {short_target}",
"",
"build {target_o}: compile_fortran_{id} {target_F90} | {list_of_modules} {list_of_includes}",
2015-06-01 14:33:24 +02:00
" short_in = {short_target_F90}",
2015-06-01 14:21:41 +02:00
" short_out = {short_target_o}",
"",
"build {target_module_o}: compile_fortran_{id} {target_module_F90}",
2015-06-01 14:33:24 +02:00
" short_in = {short_target_module_F90}",
2015-06-01 14:21:41 +02:00
" short_out = {short_target_module_o}",
"",
2015-05-28 00:28:17 +02:00
] )
result = result.format(
2015-06-01 14:21:41 +02:00
id = irp_id ,
list_of_includes = list_of_includes ,
list_of_modules = list_of_modules ,
list_of_o = list_of_o ,
2015-06-01 14:33:24 +02:00
short_target_F90 = os.path.split(target_F90)[1] ,
short_target_module_F90 = os.path.split(target_module_F90)[1] ,
short_target_module_o = os.path.split(target_module_o)[1] ,
2015-06-01 14:21:41 +02:00
short_target = name ,
2015-06-01 14:33:24 +02:00
short_target_o = os.path.split(target_o)[1] ,
2015-06-01 14:21:41 +02:00
target_F90 = target_F90 ,
target_module_F90 = target_module_F90 ,
target_module_o = target_module_o ,
target_o = target_o ,
2020-12-06 20:48:35 +01:00
target = target
2015-05-28 00:28:17 +02:00
)
return result
def create_build_non_target(t,list_of_other_o):
"""
Create the build command for the non-target module t. t is a Fmodule object.
"""
name = t.filename
2015-06-01 14:21:41 +02:00
target = dress(name,in_root=True)
short_target_o = "%s.irp.o"%name
short_target_F90 = "%s.irp.F90"%name
short_target_module_F90 = "%s.irp.module.F90"%name
short_target_module_o = "%s.irp.module.o"%name
target_o = dress(short_target_o)
target_F90 = dress(short_target_F90)
target_module_o = dress(short_target_module_o)
target_module_F90 = dress(short_target_module_F90)
2015-05-28 00:28:17 +02:00
needed_modules = [ "%s.irp.module.o"%(modules[x].filename) for x in modules \
if modules[x].name in t.needed_modules ] + [ target_module_o ]
2020-01-27 18:22:35 +01:00
list_of_modules = list(map(dress, needed_modules))
2015-05-28 00:28:17 +02:00
list_of_modules = ' '.join(list_of_modules)
list_of_externals = ' '.join([ dress(x,in_root=True) for x in list_of_other_o ])
2020-01-27 18:22:35 +01:00
list_of_includes = ' '.join([dress(x,in_root=True) for x in t.includes])
2015-05-28 00:28:17 +02:00
2015-06-01 14:21:41 +02:00
result = '\n'.join(
2020-12-06 20:48:35 +01:00
[
2015-06-01 14:21:41 +02:00
"build {target_o}: compile_fortran_{id} {target_F90} | {list_of_modules} {list_of_externals}",
2015-06-01 14:33:24 +02:00
" short_in = {short_target_F90}",
2015-06-01 14:21:41 +02:00
" short_out = {short_target}",
"",
"build {target_module_o}: compile_fortran_{id} {target_module_F90} | {list_of_externals} {list_of_includes}",
2015-06-01 14:33:24 +02:00
" short_in = {short_target_F90}",
2015-06-01 14:21:41 +02:00
" short_out = {short_target_o}",
"",
2015-05-28 00:28:17 +02:00
] )
result = result.format(
2015-06-01 14:21:41 +02:00
id = irp_id ,
list_of_externals = list_of_externals ,
list_of_includes = list_of_includes ,
list_of_modules = list_of_modules ,
2015-06-01 14:33:24 +02:00
short_target_F90 = os.path.split(target_F90)[1] ,
2015-06-01 14:21:41 +02:00
short_target = name ,
2015-06-01 14:33:24 +02:00
short_target_o = os.path.split(target_o)[1] ,
2015-05-28 00:28:17 +02:00
target_F90 = target_F90 ,
target_module_F90 = target_module_F90 ,
2015-06-01 14:21:41 +02:00
target_module_o = target_module_o ,
2020-12-06 20:48:35 +01:00
target_o = target_o
2015-05-28 00:28:17 +02:00
)
return result
def create_build_remaining(f):
"""
Create the build command for the remaining file f. f is a file name (str).
"""
t, extension = f.rsplit('.',1)
t1 = dress(t,in_root=True)
t2 = dress(t,in_root=False)
target_i = f
target_o = "%s.o"%t
if not target_o.startswith(os.path.join(cwd,irpdir)):
target_o = target_o.replace(cwd,os.path.join(cwd,irpdir))
if extension.lower() in [ 'f', 'f90' ]:
2015-06-01 14:33:24 +02:00
result = [ "build {target_o}: compile_fortran_{id} {target_i}" ]
2015-05-28 00:28:17 +02:00
elif extension.lower() in [ 'c' ]:
2015-06-01 14:33:24 +02:00
result = [ "build {target_o}: compile_c_{id} {target_i}" ]
2015-05-28 00:28:17 +02:00
elif extension.lower() in [ 'cxx', 'cpp' ]:
2015-06-01 14:33:24 +02:00
result = [ "build {target_o}: compile_cxx_{id} {target_i}" ]
2015-05-28 00:28:17 +02:00
2020-12-06 20:48:35 +01:00
result += [ " short_in = {short_target_i}",
2015-06-01 14:33:24 +02:00
" short_out = {short_target_o}", "" ]
result = '\n'.join(result).format(
2015-05-28 00:28:17 +02:00
target_o = target_o,
2015-06-01 14:21:41 +02:00
target_i = target_i,
2015-06-01 14:33:24 +02:00
short_target_o = os.path.split(target_o)[1],
short_target_i = os.path.split(target_i)[1],
2015-06-01 14:21:41 +02:00
id = irp_id
2015-05-28 00:28:17 +02:00
)
return result
def create_irpf90_make(targets):
targets = ' '.join(targets)
2015-06-10 12:10:14 +02:00
result = """NINJA += -C {0}
TARGETS={1}
2015-05-28 00:28:17 +02:00
.PHONY: all clean veryclean
all:
$(NINJA)
2020-12-06 20:48:35 +01:00
$(TARGETS):
2015-06-10 12:10:14 +02:00
$(NINJA) $(PWD)/$@
2015-05-28 00:28:17 +02:00
clean:
$(NINJA) -t clean
veryclean: clean
rm -rf IRPF90_temp/ IRPF90_man/ irpf90.make irpf90_entities dist tags
""".format(irpdir, targets)
2020-01-27 18:43:22 +01:00
import makefile
2015-05-28 00:28:17 +02:00
with open(makefile.IRPF90_MAKE,'w') as file:
file.write(result)
def run():
2015-06-05 18:32:38 +02:00
output = [ "builddir = %s"%os.path.join(cwd,irpdir) ]
2015-05-28 00:28:17 +02:00
# Environment variables
try: FC = os.environ["FC"]
2015-06-03 15:12:30 +02:00
except KeyError: FC="gfortran -ffree-line-length-none"
2015-05-28 00:28:17 +02:00
2020-12-06 20:48:35 +01:00
try: ARCHIVE = os.environ["ARCHIVE"]
except KeyError: ARCHIVE=AR
2015-06-01 14:33:24 +02:00
2015-05-28 00:28:17 +02:00
try: CC = os.environ["CC"]
2015-06-03 15:12:30 +02:00
except KeyError: CC="gcc"
2015-05-28 00:28:17 +02:00
try: CXX = os.environ["CXX"]
2015-06-03 15:12:30 +02:00
except KeyError: CXX="g++"
2015-05-28 00:28:17 +02:00
2015-06-10 12:10:14 +02:00
includes = [ "-I %s"%(i) for i in command_line.include_dir ]
2015-05-28 00:28:17 +02:00
FC += " "+' '.join(includes)
CC += " "+' '.join(includes)
CXX += " "+' '.join(includes)
2020-12-06 20:48:35 +01:00
2015-05-28 00:28:17 +02:00
try: SRC = os.environ["SRC"].split()
except KeyError: SRC=[]
try: OBJ = os.environ["OBJ"].split()
except KeyError: OBJ=[]
try: LIB = os.environ["LIB"].split()
except KeyError: LIB=[]
try: FCFLAGS = os.environ["FCFLAGS"].split()
except KeyError: FCFLAGS = [ "-O2" ]
try: CFLAGS = os.environ["CFLAGS"].split()
except KeyError: CFLAGS = [ "-O2" ]
try: CXXFLAGS = os.environ["CXXFLAGS"].split()
except KeyError: CXXFLAGS = [ "-O2" ]
FCFLAGS = ' '.join(FCFLAGS)
CFLAGS = ' '.join(CFLAGS)
CXXFLAGS = ' '.join(CXXFLAGS)
LIB = ' '.join(LIB)
# Rules
2020-12-06 20:48:35 +01:00
t = [ "rule compile_fortran_{id}",
" command = {FC} {FCFLAGS} -c $in -o $out",
" description = F : $short_in -> $short_out",
2015-06-01 14:21:41 +02:00
"",
2020-12-06 20:48:35 +01:00
"rule compile_touches_{id}",
2015-06-10 12:10:14 +02:00
" command = {FC} -c $in -o $out",
2020-12-06 20:48:35 +01:00
" description = F : $short_in -> $short_out",
2015-05-28 00:28:17 +02:00
"",
"",
2015-06-01 14:21:41 +02:00
"rule compile_c_{id}" ,
2020-12-06 20:48:35 +01:00
" command = {CC} {CFLAGS} -c $in -o $out",
" description = C : $short_in -> $short_out",
2015-05-28 00:28:17 +02:00
"",
2020-12-06 20:48:35 +01:00
"rule compile_cxx_{id}",
" command = {CXX} {CXXFLAGS} -c $in -o $out",
" description = C++ : $short_in -> $short_out",
2015-05-28 00:28:17 +02:00
"",
2020-12-06 20:48:35 +01:00
"rule link_lib_{id}",
" command = {ARCHIVE} $out $in" ,
" description = Link: $short_out",
2015-06-01 14:33:24 +02:00
"",
2020-12-06 20:48:35 +01:00
"rule link_{id}",
2015-06-01 14:21:41 +02:00
" command = {FC} $in {LIB} -o $out" ,
2020-12-06 20:48:35 +01:00
" description = Link: $short_out"]
output += [ '\n'.join(t).format(id=irp_id, FC=FC, FCFLAGS=FCFLAGS, LIB=LIB, CXX=CXX, CXXFLAGS=CXXFLAGS, CC=CC, CFLAGS=CFLAGS, ARCHIVE=ARCHIVE) ]
2015-05-28 00:28:17 +02:00
# All modules : list of Fmodule objects
l_mod = list( modules.values() )
# Modules that are not targets
l_non_targets = [ x for x in l_mod if not x.is_main ]
# Common object/source files
l_common_o = [ "irp_touches.irp.o" ] + \
[ "{0}.irp.o".format(x.filename) for x in l_non_targets ] + \
[ "{0}.irp.module.o".format(x.filename) for x in l_non_targets ]
l_common_s = []
2017-09-18 15:19:59 +02:00
if command_line.do_debug:
2015-05-28 00:28:17 +02:00
l_common_o += [ "irp_stack.irp.o" ]
l_common_s += [ "irp_stack.irp.F90" ]
if command_line.do_openmp:
l_common_o += [ "irp_locks.irp.o" ]
l_common_s += [ "irp_locks.irp.F90" ]
if command_line.do_profile:
2015-12-02 16:20:50 +01:00
l_common_o += [ "irp_profile.irp.o", "irp_rdtsc.o" ]
l_common_s += [ "irp_profile.irp.F90", "irp_rdtsc.c" ]
2015-05-28 00:28:17 +02:00
2020-01-27 18:22:35 +01:00
l_common_o = list(map(dress,l_common_o)) + [dress(x,in_root=True) for x in OBJ]
l_common_s = list(map(dress,l_common_s)) + [dress(x,in_root=True) for x in SRC]
2015-05-28 00:28:17 +02:00
# IRP_touches
output.append(create_build_touches(l_common_o[1:]))
# All targets : list of Fmodule objects
l_targets = [ x for x in l_mod if x.is_main ]
# Create lines
for i in l_non_targets:
output.append (create_build_non_target(i,OBJ))
for i in l_targets:
output.append(create_build_target(i, l_common_o))
# Remaining files
for i in l_common_s:
output.append(create_build_remaining(i))
2020-12-06 20:48:35 +01:00
2021-05-19 18:36:43 +02:00
text = '\n\n'.join(output)
text = text.replace(cwd+"/IRPF90_temp","$T")
text = text.replace(cwd,"$X")
2015-05-28 00:28:17 +02:00
with open(FILENAME,'w') as f:
2021-05-19 18:36:43 +02:00
f.write("X="+cwd+"\nT="+cwd+"/IRPF90_temp\n")
f.write(text)
2015-05-28 00:28:17 +02:00
f.write('\n')
2015-06-01 16:37:02 +02:00
create_irpf90_make([ x.filename for x in l_targets ] + [ os.path.join(irpdir,'irpf90.a') ] )
2015-05-28 00:28:17 +02:00
return