我正在编写某物,就像C++的交互式教程。本教程将由两部分组成:一部分被编译成一个库(我使用Scon构建它),另一部分(课程)随教程一起随教程一起提供,由最终用户编译。我目前正在寻找一个好的,简单的方法,人们建立这些经验教训。
基本上,第二部分是一个目录,其中包含所有的经验教训,每个都在自己的目录中。每堂课都至少有一个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/
等)运行编译命令。
考虑到项目的其余部分是用Scon构建的,因此将其用于此部分也是有意义的。然而,Scon在运行它的目录中搜索SConstruct
文件:在每个教程目录中放置一个SConstruct
文件,以及在给出一般规则的all_lessons/
目录中放置一个SConscript
是可以接受的吗?这似乎违背了Scon期望项目组织的典型方式:这种方法的潜在缺陷是什么?我是否可以放置一个SConstruct文件而不是SConscript文件,从而可以从任何一个目录构建(我猜,使用导出来避免无休止的递归)?
另外,我可能在某个时候想要用生成必要文件的lesson.cpp
来代替lesson.py
;Scon允许我用构建器轻松地完成这个任务吗?还是有一个更方便的框架?
最后,我想得到以下内容(或等效于不同的构建系统):
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
在scons all
目录中运行all_lessons
需要:
even_or_odd/lesson.py
生成even_or_odd/lesson.cpp
。user_created_add.cpp
也需要编译。在even_or_odd/
中运行even_or_odd/
,或者在all_lessons/
中运行scons even_or_odd
,应该生成与上面相同的可执行文件(相同的编译标志)。
摘要:
SConscript
文件高于SConstruct
文件时,Scons工作得好吗?当然,欢迎任何进一步的评论。
谢谢。
发布于 2011-09-06 06:57:56
实际上,您可以使用GNU的几行代码来完成这一任务。
下面是两个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
制作人员:
[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} $<
.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))
发布于 2012-05-17 21:35:18
作为一个学习技能的练习,我试着回答你的问题。不幸的是,我不是专家,所以我不能告诉你什么是最好的/理想的方式,但这里有一个方法是可行的。
使用您定义的层次结构,每个文件夹中都有一个SConstruct文件。您可以在子文件夹中运行scons
来构建该项目,也可以在顶层运行以构建所有项目(不确定如何将" all“别名为默认构建)。您可以运行scons -c
来清理项目,scon会自动找出它创建和清除的文件(包括生成的lesson.cpp)。
但是,如果您希望编译器标志从顶级文件向下传播,我认为最好使用SConscript文件--但我不确定是否单独编译这些文件。
./建造
env = Environment()
env.SConscript(dirs=['calculator', 'even_or_odd', 'helloworld'], name='SConstruct')
./计算器/SConstruct和./calculator/helloworld
env = Environment()
env.Program('program', Glob('*.cpp'))
./偶_奇数/_
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)。
./建造
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)
发布于 2011-08-19 07:13:14
编译命令必须从“课”目录中运行吗?如果没有,我将亲自创建all_ the /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 /main“等特定的课程。
https://stackoverflow.com/questions/7123431
复制