使用相似的规则构建多个可执行文件

发布于 2024-11-30 05:39:27 字数 2068 浏览 0 评论 0原文

我正在写一些类似于 C++ 交互式教程的东西。本教程将由两部分组成:一部分被编译到库中(我使用 Scons 来构建它),另一部分(课程)随教程一起提供,由最终用户编译。我目前正在寻找一种好的、简单的方法来帮助人们构建这些课程。

基本上,第二部分是一个包含所有课程的目录,每个课程都在自己的目录中。每节课至少有一个lesson.cpp和一个main.cpp文件,可能还有其他文件,直到它之后我才知道它们的存在发货——最终用户将创建这些。它看起来像这样:

all_lessons/
    helloworld/
        lesson.cpp
        main.cpp
    even_or_odd/
        lesson.cpp
        main.cpp
    calculator/
        lesson.cpp
        main.cpp
        user_created_add.cpp

每一个都需要根据几乎相同的规则进行编译,并且编译命令应该可以从课程目录之一运行(helloworld/等) .)。

鉴于项目的其余部分是使用 Scons 构建的,因此在这部分中使用它也是有意义的。但是,Scons 在运行它的目录中搜索 SConstruct 文件:是否可以在每个课程目录中放置一个 SConstruct 文件以及一个 SConscriptall_lessons/目录中给出了一般规则?这似乎违背了 Scons 期望的项目组织方式:这种方法有哪些潜在的陷阱?我可以放置一个 SConstruct 文件而不是 SConscript 文件,从而可以从任一目录进行构建(我猜,使用导出来避免无限递归)?

另外,我可能在某些时候想要用生成必要文件的 lesson.py 替换 lesson.cpp ; Scons 是否允许我使用构建器轻松完成此操作,或者是否有一个更方便的框架?

最后,我希望得到以下结果(或不同构建系统的等效结果):

all_lessons/
    SConstruct
    helloworld/
        SConstruct
        lesson.cpp
        main.cpp
    even_or_odd/
        SConstruct
        lesson.py
        main.cpp
    calculator/
        SConstruct
        lesson.cpp
        main.cpp
        user_created_add.cpp

all_lessons 目录中运行 scons all 需要:

  • 运行 Even_or_odd/lesson.py 生成 even_or_odd/lesson.cpp
  • 意识到 user_created_add.cpp 也需要编译。
  • 为每节课生成一个可执行文件。

even_or_odd/ 中运行 scons 或在 all_lessons/ 中运行 scons Even_or_odd 应该会生成与上面相同的可执行文件(相同的编译标志)。

摘要:

  1. Scons 适合/有能力做到这一点吗?
  2. SConscript 文件位于 SConstruct 文件之上时,Scons 是否可以正常工作?
  3. Scons 是否可以很好地与一个项目的多个 SConstrcut 文件配合使用,并相互进行 SConscripting?
  4. Scons构建器系统是否适合使用Python脚本生成C++文件?
  5. 使用不同的构建系统/编写我自己的构建框架有什么优势吗?

当然,欢迎任何进一步的评论。

谢谢。

I am writing something like an interactive tutorial for C++. The tutorial will consist of two parts: one is compiled into a library (I'm using Scons to build that), and the other (the lessons) is shipped with the tutorial to be compiled by the end user. I'm currently looking for a good, easy way for people to build these lessons.

Basically, the second part is a directory with all the lessons in it, each in its own directory. Each lesson will have at least a lesson.cpp and a main.cpp file, there may be also other files, the existence of which I will not know until after it is shipped -- the end user will create these. It will look something like this:

all_lessons/
    helloworld/
        lesson.cpp
        main.cpp
    even_or_odd/
        lesson.cpp
        main.cpp
    calculator/
        lesson.cpp
        main.cpp
        user_created_add.cpp

Each of these will need to be compiled according to almost the same rules, and the command for compiling should be possible to run from one of the lesson directories (helloworld/, etc.).

Seeing as the rest of the project is built with Scons, it would make sense to use it for this part, too. However, Scons searches for the SConstruct file in the directory it is run from: would it be acceptable to put a SConstruct file in each lesson directory, plus a SConscript in the all_lessons/ directory that gives the general rules? This seems to go against the typical way Scons expects projects to be organised: what are the potential pitfalls of this approach? Could I put a SConstruct file instead of the SConscript one, and thereby make it possible to build from either directory (using exports to avoid endless recursion, I'm guessing)?

Also, I may at some point want to replace the lesson.cpp with a lesson.py that generates the necessary files; will Scons allow me to do this easily with builders, or is there a framework that would be more convenient?

In the end, I want to end up with the following (or equivalent with different build systems):

all_lessons/
    SConstruct
    helloworld/
        SConstruct
        lesson.cpp
        main.cpp
    even_or_odd/
        SConstruct
        lesson.py
        main.cpp
    calculator/
        SConstruct
        lesson.cpp
        main.cpp
        user_created_add.cpp

Running scons all in the all_lessons directory would need to:

  • Run even_or_odd/lesson.py to generate even_or_odd/lesson.cpp.
  • Realise that user_created_add.cpp also needs to be compiled.
  • Produce an executable for each lesson.

Running scons in even_or_odd/, or scons even_or_odd in all_lessons/ should produce an executable identical to the one above (same compile flags).

Summary:

  1. Is Scons suitable for/capable of this?
  2. Does Scons work well when SConscript files are above SConstruct files?
  3. Does Scons work well with multiple SConstrcut files for one project, SConscripting each other?
  4. Is the Scons builder system suitable for using Python scripts to generate C++ files?
  5. Is there any advantage of using a different build system/writing my own build framework that I'm missing?

Any further comments are, of course, welcome.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

花开半夏魅人心 2024-12-07 05:39:27

实际上,您可以通过几行 GNU Make 来完成此操作。

下面是两个 makefile,允许从 all_lessons 目录和单个项目目录进行构建和清理。它假定该目录中的所有 C++ 源代码都包含一个以其目录命名的可执行文件。当从顶级源目录(all_lessons)构建和清理时,它会构建并清理所有项目。当从项目目录构建和清理时,它仅构建和清理项目的二进制文件。

这些 makefile 还会自动生成依赖项并且完全可并行化(make -j 友好)。

对于以下示例,我使用了与您相同的源文件结构:

$ find all_lessons
all_lessons
all_lessons/even_or_odd
all_lessons/even_or_odd/main.cpp
all_lessons/Makefile
all_lessons/helloworld
all_lessons/helloworld/lesson.cpp
all_lessons/helloworld/main.cpp
all_lessons/project.mk
all_lessons/calculator
all_lessons/calculator/lesson.cpp
all_lessons/calculator/user_created_add.cpp
all_lessons/calculator/main.cpp

为了能够从单独的项目目录构建,project.mk 必须首先符号链接为 project/Makefile

[all_lessons]$ cd all_lessons/calculator/
[calculator]$ ln -s ../project.mk Makefile
[helloworld]$ cd ../helloworld/
[helloworld]$ ln -s ../project.mk Makefile
[even_or_odd]$ cd ../even_or_odd/
[even_or_odd]$ ln -s ../project.mk Makefile

让我们构建一个项目:

[even_or_odd]$ make
make -C .. project_dirs=even_or_odd all
make[1]: Entering directory `/home/max/src/all_lessons'
g++ -c -o even_or_odd/main.o -Wall -Wextra   -MD -MP -MF even_or_odd/main.d even_or_odd/main.cpp
g++ -o even_or_odd/even_or_odd even_or_odd/main.o  
make[1]: Leaving directory `/home/max/src/all_lessons'
[even_or_odd]$ ./even_or_odd
hello, even_or_odd

现在构建所有项目:

[even_or_odd]$ cd ..
[all_lessons]$ make
g++ -c -o calculator/lesson.o -Wall -Wextra   -MD -MP -MF calculator/lesson.d calculator/lesson.cpp
g++ -c -o calculator/user_created_add.o -Wall -Wextra   -MD -MP -MF calculator/user_created_add.d calculator/user_created_add.cpp
g++ -c -o calculator/main.o -Wall -Wextra   -MD -MP -MF calculator/main.d calculator/main.cpp
g++ -o calculator/calculator calculator/lesson.o calculator/user_created_add.o calculator/main.o  
g++ -c -o helloworld/lesson.o -Wall -Wextra   -MD -MP -MF helloworld/lesson.d helloworld/lesson.cpp
g++ -c -o helloworld/main.o -Wall -Wextra   -MD -MP -MF helloworld/main.d helloworld/main.cpp
g++ -o helloworld/helloworld helloworld/lesson.o helloworld/main.o  
[all_lessons]$ calculator/calculator 
hello, calculator
[all_lessons]$ helloworld/helloworld
hello, world

清理一个项目:

[all_lessons]$ cd helloworld/
[helloworld]$ make clean
make -C .. project_dirs=helloworld clean
make[1]: Entering directory `/home/max/src/all_lessons'
rm -f helloworld/lesson.o helloworld/main.o helloworld/main.d helloworld/lesson.d helloworld/helloworld
make[1]: Leaving directory `/home/max/src/all_lessons'

清理所有项目:

[helloworld]$ cd ..
[all_lessons]$ make clean
rm -f calculator/lesson.o calculator/user_created_add.o calculator/main.o even_or_odd/main.o helloworld/lesson.o helloworld/main.o calculator/user_created_add.d calculator/main.d calculator/lesson.d even_or_odd/main.d  calculator/calculator even_or_odd/even_or_odd helloworld/helloworld

makefiles:

[all_lessons]$ cat project.mk 
all :
% : forward_ # build any target by forwarding to the main makefile
    $(MAKE) -C .. project_dirs=$(notdir ${CURDIR}) $@
.PHONY : forward_

[all_lessons]$ cat Makefile 
# one directory per project, one executable per directory
project_dirs := $(shell find * -maxdepth 0 -type d )

# executables are named after its directory and go into the same directory
exes := $(foreach dir,${project_dirs},${dir}/${dir})

all : ${exes}

#  the rules

.SECONDEXPANSION:

objects = $(patsubst %.cpp,%.o,$(wildcard $(dir ${1})*.cpp))

# link
${exes} : % : $(call objects,$*) Makefile
    g++ -o $@ $(filter-out Makefile,$^) ${LDFLAGS} ${LDLIBS}

# compile .o and generate dependencies
%.o : %.cpp Makefile
    g++ -c -o $@ -Wall -Wextra ${CPPFLAGS} ${CXXFLAGS} -MD -MP -MF ${@:.o=.d} 
lt;

.PHONY: clean

clean :
    rm -f $(foreach exe,${exes},$(call objects,${exe})) $(foreach dir,${project_dirs},$(wildcard ${dir}/*.d)) ${exes}

# include auto-generated dependency files
-include $(foreach dir,${project_dirs},$(wildcard ${dir}/*.d))

You can actually do this with a few lines of GNU Make.

Below are two makefiles that allow building and cleaning from all_lessons directory and individual project directories. It assumes that all C++ sources in that directory comprise an executable file which gets named after its directory. When building and cleaning from the top level source directory (all_lessons) it builds and cleans all the projects. When building and cleaning from a project's directory it only builds and cleans the project's binaries.

These makefiles also automatically generate dependencies and are fully parallelizable (make -j friendly).

For the following example I used the same source file structure as you have:

$ find all_lessons
all_lessons
all_lessons/even_or_odd
all_lessons/even_or_odd/main.cpp
all_lessons/Makefile
all_lessons/helloworld
all_lessons/helloworld/lesson.cpp
all_lessons/helloworld/main.cpp
all_lessons/project.mk
all_lessons/calculator
all_lessons/calculator/lesson.cpp
all_lessons/calculator/user_created_add.cpp
all_lessons/calculator/main.cpp

To be able to build from individial project directories project.mk must be symlinked as project/Makefile first

[all_lessons]$ cd all_lessons/calculator/
[calculator]$ ln -s ../project.mk Makefile
[helloworld]$ cd ../helloworld/
[helloworld]$ ln -s ../project.mk Makefile
[even_or_odd]$ cd ../even_or_odd/
[even_or_odd]$ ln -s ../project.mk Makefile

Let's build one project:

[even_or_odd]$ make
make -C .. project_dirs=even_or_odd all
make[1]: Entering directory `/home/max/src/all_lessons'
g++ -c -o even_or_odd/main.o -Wall -Wextra   -MD -MP -MF even_or_odd/main.d even_or_odd/main.cpp
g++ -o even_or_odd/even_or_odd even_or_odd/main.o  
make[1]: Leaving directory `/home/max/src/all_lessons'
[even_or_odd]$ ./even_or_odd
hello, even_or_odd

Now build all projects:

[even_or_odd]$ cd ..
[all_lessons]$ make
g++ -c -o calculator/lesson.o -Wall -Wextra   -MD -MP -MF calculator/lesson.d calculator/lesson.cpp
g++ -c -o calculator/user_created_add.o -Wall -Wextra   -MD -MP -MF calculator/user_created_add.d calculator/user_created_add.cpp
g++ -c -o calculator/main.o -Wall -Wextra   -MD -MP -MF calculator/main.d calculator/main.cpp
g++ -o calculator/calculator calculator/lesson.o calculator/user_created_add.o calculator/main.o  
g++ -c -o helloworld/lesson.o -Wall -Wextra   -MD -MP -MF helloworld/lesson.d helloworld/lesson.cpp
g++ -c -o helloworld/main.o -Wall -Wextra   -MD -MP -MF helloworld/main.d helloworld/main.cpp
g++ -o helloworld/helloworld helloworld/lesson.o helloworld/main.o  
[all_lessons]$ calculator/calculator 
hello, calculator
[all_lessons]$ helloworld/helloworld
hello, world

Clean one project:

[all_lessons]$ cd helloworld/
[helloworld]$ make clean
make -C .. project_dirs=helloworld clean
make[1]: Entering directory `/home/max/src/all_lessons'
rm -f helloworld/lesson.o helloworld/main.o helloworld/main.d helloworld/lesson.d helloworld/helloworld
make[1]: Leaving directory `/home/max/src/all_lessons'

Clean all projects:

[helloworld]$ cd ..
[all_lessons]$ make clean
rm -f calculator/lesson.o calculator/user_created_add.o calculator/main.o even_or_odd/main.o helloworld/lesson.o helloworld/main.o calculator/user_created_add.d calculator/main.d calculator/lesson.d even_or_odd/main.d  calculator/calculator even_or_odd/even_or_odd helloworld/helloworld

The makefiles:

[all_lessons]$ cat project.mk 
all :
% : forward_ # build any target by forwarding to the main makefile
    $(MAKE) -C .. project_dirs=$(notdir ${CURDIR}) $@
.PHONY : forward_

[all_lessons]$ cat Makefile 
# one directory per project, one executable per directory
project_dirs := $(shell find * -maxdepth 0 -type d )

# executables are named after its directory and go into the same directory
exes := $(foreach dir,${project_dirs},${dir}/${dir})

all : ${exes}

#  the rules

.SECONDEXPANSION:

objects = $(patsubst %.cpp,%.o,$(wildcard $(dir ${1})*.cpp))

# link
${exes} : % : $(call objects,$*) Makefile
    g++ -o $@ $(filter-out Makefile,$^) ${LDFLAGS} ${LDLIBS}

# compile .o and generate dependencies
%.o : %.cpp Makefile
    g++ -c -o $@ -Wall -Wextra ${CPPFLAGS} ${CXXFLAGS} -MD -MP -MF ${@:.o=.d} 
lt;

.PHONY: clean

clean :
    rm -f $(foreach exe,${exes},$(call objects,${exe})) $(foreach dir,${project_dirs},$(wildcard ${dir}/*.d)) ${exes}

# include auto-generated dependency files
-include $(foreach dir,${project_dirs},$(wildcard ${dir}/*.d))
蓝梦月影 2024-12-07 05:39:27

作为学习 scons 的练习,我试图回答你的问题。不幸的是,我不是专家,所以我不能告诉你什么是最好/理想的方法,但这是一种有效的方法。

  1. Scons适合适合/能够做到这一点。 (这正是构建工具的用途。)
  2. 不适用。 (我不知道。)
  3. Scons 似乎可以很好地工作一个项目的多个 SConstrcut 文件,SConscripting 彼此。
  4. Scons 构建器系统可以使用Python 脚本生成C++ 文件。
  5. 不同的构建系统?每个人都有自己的。

使用您定义的层次结构,每个文件夹中都有一个 SConstruct 文件。您可以在子文件夹中运行 scons 来构建该项目,或者在顶层运行 scons 来构建所有项目(不确定如何将“all”别名为默认构建)。您可以运行 scons -c 来清理项目,scons 会自动找出它创建的文件并清理它们(包括生成的 Lesson.cpp)。

但是,如果您希望编译器标志从顶级文件向下传播,我认为最好使用 SConscript 文件 - 除非我不确定是否要自行编译这些文件。

./SConstruct

env = Environment()
env.SConscript(dirs=['calculator', 'even_or_odd', 'helloworld'], name='SConstruct')

./calculator/SConstruct 和 ./calculator/helloworld

env = Environment()
env.Program('program', Glob('*.cpp'))

./even_or_odd/SConstruct

env = Environment()

def add_compiler_builder(env):
    # filename transformation
    suffix = '.cpp'
    src_suffix = '.py'

    # define the build method
    rule = 'python $SOURCE $TARGET'

    bld = Builder(action = rule,
                  suffix = suffix,
                  src_suffix = src_suffix)
    env.Append(BUILDERS = {'Lesson' : bld})

    return env

add_compiler_builder(env)

env.Lesson('lesson.py')
env.Program('program', Glob('*.cpp'))

使用 SConscripts

我将子文件夹的 SConstructs 转换为 SConscripts,并且可以将代码构建细节从子文件夹中取出,但随后您需要运行 scons -u 在子文件夹中构建(向上搜索根 SConstruct)。

./SConstruct

def default_build(env):
    env.Program('program', Glob('*.cpp'))

env = Environment()
env.default_build = default_build

Export('env')
env.SConscript(dirs=['calculator', 'even_or_odd', 'helloworld'])

./helloworld/SConscript 等...

Import('env')
env.default_build(env)

As an exercise in learning scons, I've tried to answer your question. Unfortunately, I'm no expert, so I can't tell you what's the best/ideal way, but here's a way that works.

  1. Scons is suitable for/capable of this. (This is exactly what build tools are for.)
  2. Not applicable. (I don't know.)
  3. Scons seems to work well with multiple SConstrcut files for one project, SConscripting each other.
  4. The Scons builder system can use Python scripts to generate C++ files.
  5. A different build system? To each his own.

Using the hierarchy you defined, there's a SConstruct file in each folder. You can run scons in a subfolder to build that project or at the top level to build all projects (not sure how you'd alias "all" to the default build). You can run scons -c to clean the project and scons automatically figures out which files it created and cleans them (including the generated lesson.cpp).

However, if you want compiler flags to propagate from the top-level file down, I think it's better to use SConscript files -- except I'm not sure about making these compile on their own.

./SConstruct

env = Environment()
env.SConscript(dirs=['calculator', 'even_or_odd', 'helloworld'], name='SConstruct')

./calculator/SConstruct and ./calculator/helloworld

env = Environment()
env.Program('program', Glob('*.cpp'))

./even_or_odd/SConstruct

env = Environment()

def add_compiler_builder(env):
    # filename transformation
    suffix = '.cpp'
    src_suffix = '.py'

    # define the build method
    rule = 'python $SOURCE $TARGET'

    bld = Builder(action = rule,
                  suffix = suffix,
                  src_suffix = src_suffix)
    env.Append(BUILDERS = {'Lesson' : bld})

    return env

add_compiler_builder(env)

env.Lesson('lesson.py')
env.Program('program', Glob('*.cpp'))

Using SConscripts

I convert the subfolder's SConstructs to SConscripts and can lift the code build specifics out of the subfolders, but then you need to run scons -u to build in a subfolder (to search upwards for the root SConstruct).

./SConstruct

def default_build(env):
    env.Program('program', Glob('*.cpp'))

env = Environment()
env.default_build = default_build

Export('env')
env.SConscript(dirs=['calculator', 'even_or_odd', 'helloworld'])

./helloworld/SConscript, etc...

Import('env')
env.default_build(env)
有深☉意 2024-12-07 05:39:27

编译命令是否必须从课程目录运行?如果没有,那么我会亲自创建包含以下内容的 all_lessons/makefile:

lessons = helloworld even_or_odd calculator

all: $(lessons)

# for each $lesson, the target is $lesson/main built from $lesson/main.cpp and $lesson/lesson.cpp
# NB: the leading space on the second line *must* be a tab character
$(lessons:%=%/main): %/main: %/main.cpp %/lesson.cpp
   g++ -W -Wall $+ -o $@

然后可以在 all_lessons 目录中使用“make”或“make all”构建所有课程,或者使用例如“make helloworld/main”构建特定课程。

Is it essential that the command for compiling be run from the lesson directory? If not then I would personally create all_lessons/makefile with the following contents:

lessons = helloworld even_or_odd calculator

all: $(lessons)

# for each $lesson, the target is $lesson/main built from $lesson/main.cpp and $lesson/lesson.cpp
# NB: the leading space on the second line *must* be a tab character
$(lessons:%=%/main): %/main: %/main.cpp %/lesson.cpp
   g++ -W -Wall $+ -o $@

All lessons could then be built with "make" or "make all" in the all_lessons directory, or a specific lesson with e.g. "make helloworld/main".

合约呢 2024-12-07 05:39:27

据我发现,这是可用的最佳解决方案:

目录以相同的方式构建,但课程没有多个 SConstruct 文件,而是有一个 SConscript将每个文件归档,其中默认值将根据需要被覆盖。 SConstruct 文件由外部脚本根据需要生成,并调用 SCons。

概述:

all_lessons/
    helloworld/
        SConscript
        lesson.cpp
        main.cpp
    even_or_odd/
        SConscript
        lesson.py
        main.cpp
    calculator/
        SConscript
        lesson.cpp
        main.cpp
        user_created_add.cpp

使用GlobSConscript文件可以编译所有带有cpp扩展名的文件。它还可以使用生成器(调用简单命令的生成器或成熟的生成器)来生成课程,这意味着甚至可以将课程存储为元数据并当场生成。

所以,回答问题:

  1. 是的。
  2. 我不知道,但这不是达到此目的所必需的。
  3. 据我所知,没有(相对于 SConstruct 的路径问题等)。
  4. 是的,有多种选择。
  5. 我不知道。

建议方法的缺点:这确实需要单独制作元构建系统。可以指定选项的文件数量较多,并且 SConscript 文件给错误提供了很大的空间。

As far as I have found, this is the best solution available:

The directory is structured in the same way, but instead of having multiple SConstruct files, the lessons have a SConscript file each, where defaults are overridden as necessary. The SConstruct files are generated by an external script as necessary, and SCons is invoked.

An overview:

all_lessons/
    helloworld/
        SConscript
        lesson.cpp
        main.cpp
    even_or_odd/
        SConscript
        lesson.py
        main.cpp
    calculator/
        SConscript
        lesson.cpp
        main.cpp
        user_created_add.cpp

Using Glob, the SConscript file can make all files with the cpp extension be compiled. It can also use a builder (either one invoking a simple command, or a fully-fledged one) that will generate the lesson, meaning it's possible to even just store the lesson as metadata and have it generated on the spot.

So, to answer the questions:

  1. Yes.
  2. I don't know, but it is not required for the purpose of this.
  3. As far as I have seen, no (issues with paths relative to SConstruct, amongst other things).
  4. Yes, with several options being available.
  5. I don't know.

Downsides to the suggested approach: this does require making a meta-build system separately. The number of files where options can be specified is higher, and the SConscript files give a lot of room for error.

好多鱼好多余 2024-12-07 05:39:27

这是我的方法。

# SConstruct or SConscript

def getSubdirs(dir) :   
    lst = [ name for name in os.listdir(dir) if os.path.isdir(os.path.join(dir, name)) and name[0] != '.' ]
    return lst

env = Environment()
path_to_lessons = '' # path to lessons
# configure your environment, set common rules and parameters for all lessons
for lesson in getSubdirs(path_to_lessons) :
    lessonEnv = env.Clone()
    # configure specific lesson, for example i'h ve checked SConscript file in lesson dir
    # and if it exist, execute it with lessonEnv and append env specific settings
    if File(os.path.join(path_to_lessons, lesson, 'lesson.scons')).exists() :
        SConscript(os.path.join(lesson, 'lesson.scons', export = ['lessonEnv'])

    # add lesson directory to include path
    lessonEnv.Append(CPPPATH = os.path.join(path_to_lessons, lesson));

    lessonEnv.Program(lesson, Glob(os.path.join(path_to_lessons, lesson, '*.cpp'))

现在您拥有:

  • env - core 包含通用规则和参数的环境
    所有课程
  • LessonEnv - 核心环境的克隆,但如果你有
    Lesson.scons 在特定课程目录中,您可以额外配置
    那个环境或者重写一些参数。

Here is my way.

# SConstruct or SConscript

def getSubdirs(dir) :   
    lst = [ name for name in os.listdir(dir) if os.path.isdir(os.path.join(dir, name)) and name[0] != '.' ]
    return lst

env = Environment()
path_to_lessons = '' # path to lessons
# configure your environment, set common rules and parameters for all lessons
for lesson in getSubdirs(path_to_lessons) :
    lessonEnv = env.Clone()
    # configure specific lesson, for example i'h ve checked SConscript file in lesson dir
    # and if it exist, execute it with lessonEnv and append env specific settings
    if File(os.path.join(path_to_lessons, lesson, 'lesson.scons')).exists() :
        SConscript(os.path.join(lesson, 'lesson.scons', export = ['lessonEnv'])

    # add lesson directory to include path
    lessonEnv.Append(CPPPATH = os.path.join(path_to_lessons, lesson));

    lessonEnv.Program(lesson, Glob(os.path.join(path_to_lessons, lesson, '*.cpp'))

Now you have :

  • env - core Environment that contain common rules and parameters for
    all lessons
  • lessonEnv - clone of core env, but if you have
    lesson.scons in specific lesson dir, you can additional configure
    that environment or rewrite some parameters.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文