重用来自不同项目的 SConstruct 的环境

Reusing Environment from a different project's SConstruct

我得到了一个完整的源存档(称之为 legacyProject),其中有一个 SConstruct 构建脚本。这个构建脚本做了很多工作来创建一个很好的自定义 Environment,它理解微控制器的自定义工具链。它还具有一些辅助函数,可以简化为相当大的构建矩阵生成 Program 语句。

我正在启动一个相关项目,该项目可以几乎逐字重用此 Environment 和相关代码。我不想只是将所有内容复制粘贴到一个新的 SConstruct 文件中,因为原始文件可能会收到补丁(更不用说它只是代码的重复)。目前这些项目在文件系统中是并排的:

myProject/
    SConstruct
legacyProject/
    SConstruct

我可能会重新排列它们,使 legacyProject 成为 myProject 的子目录,这样我就可以使用版本控制跟踪准确的修订。

myProject/
    SConstruct
    legacyProject/
        SConstruct

有没有办法从 legacyProject/SConstruct 导入所有代码? 对于 Python 模块,这对于 import 来说很简单,但是我不知道 Scons 是否可行。我的尝试:

SConscript('legacyProject/SConstruct')

只是 returns None.

我建议将您想要共享的逻辑重新设计到您导入的 python 模块中,并在您的 SConstruct 中调用一些初始化。这将是最干净的方法(恕我直言)。

虽然您可以使用 pythons execfile()(我相信),但这是一种混乱的方式。

如果不将遗留 SConstruct 的某些功能重构到辅助文件中,我认为没有办法做到这一点。

如果您可以重构代码,那么可以使用三种可能的替代方法 - 一种是使用 SCons 中内置的现有 SConscript 机制,另一种是使用 python 模块,最后一种方法是使用站点目录选项。

通过 SConscripts 重用

假设项目结构如下:

.
├── common
│   └── SConscript
├── legacyProject
│   └── SConstruct
└── myProject
    └── SConstruct

您的 SConstruct 文件将创建一个环境,然后执行 common/SConscript,其中 returns 一个修改后的环境。例如,如果你想在公共目录中收集一些选项,你可能会得到如下内容:

# common/SConscript
Import('env')
env['CCFLAGS']  = '-Wall -Wextra -pedantic'
Return('env')

# myProject/SConstruct (similar for legacy/SConstruct)
env = Environment()
print 'before:', env['CCFLAGS']
env = SConscript('../common/SConscript', exports = 'env')
print 'after:', env['CCFLAGS']

在以下情况下选择此方法:

  • 您熟悉 SCons,但不太熟悉 Python
  • 您不想将额外的标志传递给 scons 或设置环境变量
  • 您试图不知道您正在使用 Python 的哪个安装
  • 您没有使用变体目录

通过 Python 模块重复使用

如果您要将 scons 实用程序打包为 python 包,您可以采用两种方法。

首先是使用传统的Python打包技术。周围有一些很好的指南 - 我推荐 Python Packaging User Guide. To get this working you'll need to write a setup.py,并使用 pippython setup.py install

安装

使这变得棘手的是,您可以同时安装多个 Python 和 SCons,它们通过 PATH 环境变量巧妙地耦合在一起。这可能意味着在一台机器上工作的东西可能在另一台机器上不工作。

一种更常见的方法是修改 python 用于在您的 SConstructs 中搜索模块的路径 - 从 Python 的角度来看,这是一种糟糕的做法,但更易于维护,特别是如果您的构建机器是复杂。

假设项目结构如下:

.
├── common
│   └── __init__.py
├── legacyProject
│   └── SConstruct
└── myProject
    └── SConscript

您的 python 模块可以非常简单:

# common/__init__.py
def set_warning_flags(env):
    env['CCFLAGS']  = '-Wall -Wextra -pedantic'

并且:

# myProject/SConstruct
import sys
sys.path.insert(0, '..')
import common

env = Environment()
print 'before:', env['CCFLAGS']
common.set_warning_flags(env)
print 'after:', env['CCFLAGS']

在以下情况下选择此方法:

  • 你有很多外部配置(很多构建器/复杂的环境),只需要从几个地方拉进来。
  • 您没有使用变体构建

通过 site-dir / site-init 重用

如果您想在不更改多个 SConstructs 的情况下即时添加功能,您可以使用 SCons 支持的内置可扩展性(请参阅用户手册中的部分 Where To Put Your Custom Builders and Tools or search for --site-dir=dir in the SCons Man Page

在这种情况下,您将拥有:

.
├── common
│   └── site_init.py
├── legacyProject
│   └── SConstruct
└── myProject
    └── SConstruct

其中 site_init.py 是:

# common/site_init.py
def set_warning_flags(env):
    env['CCFLAGS']  = '-Wall -Wextra -pedantic'

SConstruct 是:

env = Environment()
print 'before:', env['CCFLAGS']
set_warning_flags(env)
print 'after:', env['CCFLAGS']

但是您需要调用 SCons(从 myProject / legacyProject 目录):

scons --site-dir=../common

在以下情况下选择此方法:

  • 您想更改两个项目的构建而不更改其中任何一个的代码。