用于通用 Fortran 项目的 SCons mwe

问题描述 投票:0回答:1

我很难理解 SCons 的逻辑,即使在阅读了一些资料并花了相当多的时间编码之后也是如此。我还没有找到任何与我想要完成的任务相关的使用 SCons 的合理可理解的 Fortran 项目。我还找到了任何深入的教程或解释(官方手册并没有真正告诉后端如何工作)。

我的目标是自动编译一个Fortran项目,其源文件分散在从某个根目录开始的目录树中。

代码概要:

  1. 在目录树中查找所有 Fortran 文件
  2. 使用
    fortdepend
    生成依赖关系并区分程序和模块
  3. 告诉 SCons 对象、依赖项和程序/目标

源之间的依赖关系通过 fortdepend 解决。但我还是坚持告诉 SCons 依赖关系。由于 SCons 具有明确的 Fortran 支持,因此对于这样的通用用例,我的解决方案感觉很复杂。

这是我的

SConstruct
文件:

import os
import fortdepend as fd
from  SCons.Environment import Environment

fexts = ['.f', '.for', '.f90', '.f95', '.f03', '.f08']

def find_fortran_files(root_dir, fortran_extensions, abspath=False):
  """Find all Fortran source files in src directory and its subdirectories"""
  source_files = []
  for dir, _, files in os.walk(root_dir):
    for file in files:
      if any(file.endswith(ext) for ext in fortran_extensions):
        source_files.append( os.path.join(dir, file) if abspath else os.path.join(dir.replace(root_dir, '.'), file))
  return source_files

def fortran_source_to_object(source, fortran_extensions):
  """replace the fortran ext with .o"""
  for ext in fortran_extensions:
    if source.endswith(ext):
      return source.replace(ext, '.o')
s2o = lambda src: fortran_source_to_object(str(src), fexts)
ss2os = lambda srcs: [fortran_source_to_object(str(src), fexts) for src in srcs]


def generate_fortran_dependencies(source_files, fortran_extensions, **kwargs):
  """ use fortdepend to get dependencies """
  fproj = fd.FortranProject(files=source_files, **kwargs)
  source_deps, prog_deps = {}, {}
  for key, val in fproj.depends_by_module.items():
    _key = key.source_file.filename
    _val = [v.source_file.filename for v in val] 
    if key.unit_type=='module':
      source_deps[_key] = _val
    elif key.unit_type=='program':
      prog_deps[_key] = _val
  return source_deps, prog_deps

env = Environment(tools=['default', 'gfortran'], F90='gfortran', LINK='gfortran', LINKFLAGS='', F90FLAGS='')

all_files = find_fortran_files(os.getcwd(), fortran_extensions=fexts, abspath=False)
print('- all files found with fortran ext: ', all_files)

source_deps, prog_deps = generate_fortran_dependencies(all_files, fexts)
source_files = list(source_deps.keys())
prog_files = list(prog_deps.keys())
print('- all source deps (no progs)       ', source_deps)
print('- all program deps found           ', prog_deps)
print('- all source files (no progs)      ', source_files)
print('- all prog files                   ', prog_files)

objects = []
all_deps = {**source_deps, **prog_deps}
for src in all_deps:
    obj_path = os.path.splitext(src)[0] + '.o'
    object = env.Object(obj_path, src)
    print(f'-- tell SCons {obj_path} also depends on {all_deps[src]}')
    env.Depends(target=object, dependency = all_deps[src])
    objects.append(object)
print('- all SCons objects', [str(o) for o in objects])

for prog in prog_deps:
  prog_name = os.path.splitext(os.path.basename(prog))[0]
  print(f'-- tell SCons {prog_name} also depends on {ss2os(prog_deps[prog])}')
  env.Depends(target=prog_name, dependency = ss2os(prog_deps[prog]))

# Filter out .mod files from the objects list
objects_for_linking = [str(o[0]) for o in objects] # get only the first entry which is the object file 
print('- all SCons objects for linking', objects_for_linking)

prog_to_make = 'main'
env.Program(target=prog_to_make, source=objects_for_linking)

在下面的存储库中

https://github.com/alexksr/SconsMWE.git
有两个Python脚本,用于使用示例Fortran代码设置根目录。
init1.py
存在依赖关系,按字母顺序编译时可以满足这些依赖关系(简单,非用例)。第二个
init2.py
具有依赖性,必须明确考虑这些依赖性(
module0
取决于
module1
module2
)。对于梯子,我的代码不起作用,但结果是:

scons: Reading SConscript files ...
- all files found with fortran ext:  ['./src/module0.f90', './src/main.f90', './src/module1.f90', './src/module2.f90', './src/utils/util_module.f90']
- all source deps (no progs)        {'./src/module0.f90': ['./src/module1.f90', './src/module2.f90'], './src/module1.f90': [], './src/module2.f90': [], './src/utils/util_module.f90': []}
- all program deps found            {'./src/main.f90': ['./src/module0.f90', './src/module1.f90', './src/module2.f90', './src/utils/util_module.f90']}
- all source files (no progs)       ['./src/module0.f90', './src/module1.f90', './src/module2.f90', './src/utils/util_module.f90']
- all prog files                    ['./src/main.f90']
-- tell SCons ./src/module0.o also depends on ['./src/module1.f90', './src/module2.f90']
-- tell SCons ./src/module1.o also depends on []
-- tell SCons ./src/module2.o also depends on []
-- tell SCons ./src/utils/util_module.o also depends on []
-- tell SCons ./src/main.o also depends on ['./src/module0.f90', './src/module1.f90', './src/module2.f90', './src/utils/util_module.f90']
- all SCons objects ["['src/module0.o', 'module0.mod']", "['src/module1.o', 'module1.mod']", "['src/module2.o', 'module2.mod']", "['src/utils/util_module.o', 'util_module.mod']", "['src/main.o']"]
-- tell SCons main also depends on ['./src/module0.o', './src/module1.o', './src/module2.o', './src/utils/util_module.o']
- all SCons objects for linking ['src/module0.o', 'src/module1.o', 'src/module2.o', 'src/utils/util_module.o', 'src/main.o']
scons: done reading SConscript files.
scons: Building targets ...
gfortran -o src/module0.o -c src/module0.f90
src/module0.f90:3:8:

     use module1
        1
Fatal Error: Can't open module file 'module1.mod' for reading at (1): No such file or directory
compilation terminated.
scons: *** [src/module0.o] Error 1
scons: building terminated because of errors.

在我放弃 SCons 并回去制作之前,感谢任何帮助。

dependencies fortran scons build-tools
1个回答
0
投票

试试这个,假设您只从所有生成的源中构建一个程序。无需显式使用 Depends(),因为 SCons 会自动在程序->对象->源之间创建依赖关系。

import os

fexts = ['.f', '.for', '.f90', '.f95', '.f03', '.f08']

def find_fortran_files(root_dir, fortran_extensions, abspath=False):
  """Find all Fortran source files in src directory and its subdirectories"""
  source_files = []
  for dir, _, files in os.walk(root_dir):
    for file in files:
      if any(file.endswith(ext) for ext in fortran_extensions):
        source_files.append( os.path.join(dir, file) if abspath else os.path.join(dir.replace(root_dir, '.'), file))
  return source_files


env = Environment(tools=['default', 'gfortran'], F90='gfortran', LINK='gfortran', LINKFLAGS='', F90FLAGS='')

source_files = find_fortran_files(os.getcwd(), fortran_extensions=fexts, abspath=False)

print('- all files found with fortran ext: ', all_files)
print('- all source files (no progs)      ', source_files)


prog_to_make = 'main'
env.Program(target=prog_to_make, source=source_files)
© www.soinside.com 2019 - 2024. All rights reserved.