使用相似的规则构建多个可执行文件
我正在写一些类似于 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
文件以及一个 SConscript
在all_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
应该会生成与上面相同的可执行文件(相同的编译标志)。
摘要:
- Scons 适合/有能力做到这一点吗?
- 当
SConscript
文件位于SConstruct
文件之上时,Scons 是否可以正常工作? - Scons 是否可以很好地与一个项目的多个
SConstrcut
文件配合使用,并相互进行 SConscripting? - Scons构建器系统是否适合使用Python脚本生成C++文件?
- 使用不同的构建系统/编写我自己的构建框架有什么优势吗?
当然,欢迎任何进一步的评论。
谢谢。
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 generateeven_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:
- Is Scons suitable for/capable of this?
- Does Scons work well when
SConscript
files are aboveSConstruct
files? - Does Scons work well with multiple
SConstrcut
files for one project, SConscripting each other? - Is the Scons builder system suitable for using Python scripts to generate C++ files?
- 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
实际上,您可以通过几行 GNU Make 来完成此操作。
下面是两个 makefile,允许从
all_lessons
目录和单个项目目录进行构建和清理。它假定该目录中的所有 C++ 源代码都包含一个以其目录命名的可执行文件。当从顶级源目录(all_lessons
)构建和清理时,它会构建并清理所有项目。当从项目目录构建和清理时,它仅构建和清理项目的二进制文件。这些 makefile 还会自动生成依赖项并且完全可并行化(make -j 友好)。
对于以下示例,我使用了与您相同的源文件结构:
为了能够从单独的项目目录构建,
project.mk
必须首先符号链接为project/Makefile
让我们构建一个项目:
现在构建所有项目:
清理一个项目:
清理所有项目:
makefiles:
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:
To be able to build from individial project directories
project.mk
must be symlinked asproject/Makefile
firstLet's build one project:
Now build all projects:
Clean one project:
Clean all projects:
The makefiles:
作为学习 scons 的练习,我试图回答你的问题。不幸的是,我不是专家,所以我不能告诉你什么是最好/理想的方法,但这是一种有效的方法。
使用您定义的层次结构,每个文件夹中都有一个 SConstruct 文件。您可以在子文件夹中运行 scons 来构建该项目,或者在顶层运行 scons 来构建所有项目(不确定如何将“all”别名为默认构建)。您可以运行 scons -c 来清理项目,scons 会自动找出它创建的文件并清理它们(包括生成的 Lesson.cpp)。
但是,如果您希望编译器标志从顶级文件向下传播,我认为最好使用 SConscript 文件 - 除非我不确定是否要自行编译这些文件。
./SConstruct
./calculator/SConstruct 和 ./calculator/helloworld
./even_or_odd/SConstruct
使用 SConscripts
我将子文件夹的 SConstructs 转换为 SConscripts,并且可以将代码构建细节从子文件夹中取出,但随后您需要运行 scons -u 在子文件夹中构建(向上搜索根 SConstruct)。
./SConstruct
./helloworld/SConscript 等...
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.
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 runscons -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
./calculator/SConstruct and ./calculator/helloworld
./even_or_odd/SConstruct
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
./helloworld/SConscript, etc...
编译命令是否必须从课程目录运行?如果没有,那么我会亲自创建包含以下内容的 all_lessons/makefile:
然后可以在 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:
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".
据我发现,这是可用的最佳解决方案:
目录以相同的方式构建,但课程没有多个
SConstruct
文件,而是有一个SConscript
将每个文件归档,其中默认值将根据需要被覆盖。SConstruct
文件由外部脚本根据需要生成,并调用 SCons。概述:
使用
Glob
,SConscript
文件可以编译所有带有cpp
扩展名的文件。它还可以使用生成器(调用简单命令的生成器或成熟的生成器)来生成课程,这意味着甚至可以将课程存储为元数据并当场生成。所以,回答问题:
SConstruct
的路径问题等)。建议方法的缺点:这确实需要单独制作元构建系统。可以指定选项的文件数量较多,并且
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 aSConscript
file each, where defaults are overridden as necessary. TheSConstruct
files are generated by an external script as necessary, and SCons is invoked.An overview:
Using
Glob
, theSConscript
file can make all files with thecpp
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:
SConstruct
, amongst other things).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.这是我的方法。
现在您拥有:
所有课程
Lesson.scons 在特定课程目录中,您可以额外配置
那个环境或者重写一些参数。
Here is my way.
Now you have :
all lessons
lesson.scons in specific lesson dir, you can additional configure
that environment or rewrite some parameters.