You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置SCons,使指定测试程序编译失败时不中断构建?

问题:如何让SCons忽略指定测试程序的编译失败?

我使用SConstruct文件构建C++库,并编译多个测试程序验证有效性。以下代码可正常构建测试程序:

test_sources = glob.glob(r"test/unit_tests/*.cpp")
env.Append(RPATH=root_dir)
for tsource in test_sources:
  ttarget = tsource.replace('.cpp', '.out')
  env.Program(target=ttarget, source=tsource, CPPPATH='src/', LIBS=vlib, LIBPATH='.')

但部分文件名含'mock'的测试程序是故意设计为编译失败的。我尝试用try/except块包裹编译命令:

test_sources = glob.glob(r"test/unit_tests/*.cpp")
env.Append(RPATH=root_dir)
for tsource in test_sources:
    ttarget = tsource.replace('_', '-').replace('.cpp', '.out')
    if 'mock' in os.path.basename(tsource):
        # 含mock的文件应编译失败
        try:
            env.Program(target=ttarget, source=tsource, CPPPATH='src/', LIBS=vlib, LIBPATH='.')
            sys.exit(1)
        except:
            pass
    else:
        env.Program(target=ttarget, source=tsource, CPPPATH='src/', LIBS=vlib, LIBPATH='.')

但该方法无效,SCons仍因编译错误终止,错误日志如下:

scons: Reading SConscript files ...
running with -j 2
scons: done reading SConscript files.
scons: Building targets ...
g++ -o test/unit-tests/month.out -Wl,-rpath=/home/xanthos/Software/ggdatetime test/unit_tests/month.o -L. libdatetime.so.0.1.0
g++ -o test/unit_tests/year_mock_1.o -c -std=c++17 -Wall -Wextra -Werror -pedantic -W -Wshadow -Winline -O2 -march=native --std=c++17 -Isrc test/unit_tests/year_mock_1.cpp
g++ -o test/unit_tests/year_mock_2.o -c -std=c++17 -Wall -Wextra -Werror -pedantic -W -Wshadow -Winline -O2 -march=native --std=c++17 -Isrc test/unit_tests/year_mock_2.cpp
test/unit_tests/year_mock_1.cpp: In function 'int main()':
test/unit_tests/year_mock_1.cpp:9:6: error: no match for 'operator==' (operand types are 'dso::year' and 'int')
    9 |   y1 == 2024;
      |   ~~ ^~ ~~~~
      |   |     |
      |   |     int
      |   dso::year
In file included from test/unit_tests/year_mock_1.cpp:1:
src/dtfund.hpp:1616:16: note: candidate: 'template<class DType, class, class> constexpr bool dso::operator==(DType, DType)'
 1616 | constexpr bool operator==(DType a, DType b) noexcept {
      |                ^~~~~~~~
src/dtfund.hpp:1616:16: note:   template argument deduction/substitution failed:
test/unit_tests/year_mock_1.cpp:9:9: note:   deduced conflicting types for parameter 'DType' ('dso::year' and 'int')
    9 |   y1 == 2024;
      |         ^~~~
scons: *** [test/unit_tests/year_mock_1.o] Error 1
test/unit_tests/year_mock_2.cpp: In function 'int main()':
test/unit_tests/year_mock_2.cpp:9:6: error: no match for 'operator+' (operand types are 'dso::year' and 'int')
    9 |   y1 + 2024;
      |   ~~ ^ ~~~~
      |   |    |
      |   |    int
      |   dso::year
In file included from test/unit_tests/year_mock_2.cpp:1:
src/dtfund.hpp:1751:17: note: candidate: 'template<class DType, class, class> constexpr DType dso::operator+(DType, DType)'
 1751 | constexpr DType operator+(DType _a, DType _b) noexcept {
      |                 ^~~~~~~~
src/dtfund.hpp:1751:17: note:   template argument deduction/substitution failed:
test/unit_tests/year_mock_2.cpp:9:8: note:   deduced conflicting types for parameter 'DType' ('dso::year' and 'int')
    9 |   y1 + 2024;
      |        ^~~~
scons: *** [test/unit_tests/year_mock_2.o] Error 1
scons: building terminated because of errors.

解决方案

为什么try/except无效?

env.Program()是在SCons脚本解析阶段生成构建规则,而非直接执行编译操作。编译错误发生在后续的构建执行阶段,因此try/except无法捕获这类错误,也就无法阻止SCons因失败终止。

方案一:使用ALLOW_ERRORS构建变量

SCons提供ALLOW_ERRORS变量,设置为True时,目标构建失败不会终止整个构建流程。修改mock测试的构建代码:

test_sources = glob.glob(r"test/unit_tests/*.cpp")
env.Append(RPATH=root_dir)
for tsource in test_sources:
    ttarget = tsource.replace('_', '-').replace('.cpp', '.out')
    if 'mock' in os.path.basename(tsource):
        # 允许含mock的测试编译失败,不中断整体构建
        env.Program(
            target=ttarget,
            source=tsource,
            CPPPATH='src/',
            LIBS=vlib,
            LIBPATH='.',
            ALLOW_ERRORS=True
        )
    else:
        env.Program(
            target=ttarget,
            source=tsource,
            CPPPATH='src/',
            LIBS=vlib,
            LIBPATH='.'
        )

方案二:自定义命令并忽略错误

如果需要更精细控制编译流程,可以用env.Command()手动指定编译命令,并设置ignore_errors=True忽略错误:

import os
import glob

test_sources = glob.glob(r"test/unit_tests/*.cpp")
env.Append(RPATH=root_dir)
for tsource in test_sources:
    ttarget = tsource.replace('_', '-').replace('.cpp', '.out')
    if 'mock' in os.path.basename(tsource):
        # 手动编译目标文件,忽略错误
        obj_target = tsource.replace('.cpp', '.o')
        env.Command(
            target=obj_target,
            source=tsource,
            action="$CXX $CXXFLAGS -c -o $TARGET $SOURCE",
            ignore_errors=True
        )
        # 手动链接可执行文件,忽略错误
        env.Command(
            target=ttarget,
            source=obj_target,
            action="$CXX $LINKFLAGS -o $TARGET $SOURCE $LIBS",
            ignore_errors=True
        )
    else:
        env.Program(
            target=ttarget,
            source=tsource,
            CPPPATH='src/',
            LIBS=vlib,
            LIBPATH='.'
        )

效果说明

使用上述任意方案后,含'mock'的测试程序编译失败时,SCons会记录错误信息,但不会终止整个构建流程,其他正常测试程序仍会继续编译。

内容的提问来源于stack exchange,提问作者xnth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:53:11