Reputation: 311
I am using scons to compile my project. In my project source files are in different directories. Do we need sconscript file in every directory to compile those project source files?
I tried to compile all directories with the single sconscript file. But all object files are adding to my source directory only.
I am using this function:
env.Library('libs',files_list)
If files_list contains the only file names then Obj files are generating @ variant directory.
If files_list contains the file path names then Obj files are generating @ source directory.
Can you tell me how to do this?
Upvotes: 4
Views: 6632
Reputation: 10357
I prepared an example that shows how to compile a project like yours with just one SConstruct script (no subsidiary SConscripts) using the SCons VariantDir() function. I decided to do this in a separate answer so that it would be easier to read.
The VariantDir() function isnt documented very well, so the behavior you mention regarding the placement of the compiled object files isnt straight-forward to fix. The "trick" is to refer to all of your source files in the variant directory, not in your actual source directory, as can be seen below.
Here is the structure of the source files in my project:
$ tree .
.
├── SConstruct
├── src1
│ ├── class1.cc
│ └── class1.h
├── src2
│ ├── class2.cc
│ └── class2.h
└── srcMain
└── main.cc
Here is the SConstruct:
env = Environment()
# Set the include paths
env.Append(CPPPATH = ['src1', 'src2'])
# Notice the source files are referred to in the build dir
# If you dont do this, the compiled objects will be in the src dirs
src1Sources = ['build/lib1/class1.cc']
src2Sources = ['build/lib2/class2.cc']
mainSources = ['build/mainApp/main.cc']
env.VariantDir(variant_dir = 'build/lib1', src_dir = 'src1', duplicate = 0)
env.VariantDir(variant_dir = 'build/lib2', src_dir = 'src2', duplicate = 0)
env.VariantDir(variant_dir = 'build/mainApp', src_dir = 'srcMain', duplicate = 0)
lib1 = env.Library(target = 'build/lib1/src1', source = src1Sources)
lib2 = env.Library(target = 'build/lib1/src2', source = src2Sources)
env.Program(target = 'build/mainApp/main', source = [mainSources, lib1, lib2])
Here is the compilation output:
$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o build/lib1/class1.o -c -Isrc1 -Isrc2 src1/class1.cc
ar rc build/lib1/libsrc1.a build/lib1/class1.o
ranlib build/lib1/libsrc1.a
g++ -o build/lib2/class2.o -c -Isrc1 -Isrc2 src2/class2.cc
ar rc build/lib1/libsrc2.a build/lib2/class2.o
ranlib build/lib1/libsrc2.a
g++ -o build/mainApp/main.o -c -Isrc1 -Isrc2 srcMain/main.cc
g++ -o build/mainApp/main build/mainApp/main.o build/lib1/libsrc1.a build/lib1/libsrc2.a
scons: done building targets.
And here is the resulting project structure after compiling:
$ tree .
.
├── build
│ ├── lib1
│ │ ├── class1.o
│ │ ├── libsrc1.a
│ │ └── libsrc2.a
│ ├── lib2
│ │ └── class2.o
│ └── mainApp
│ ├── main
│ └── main.o
├── SConstruct
├── src1
│ ├── class1.cc
│ └── class1.h
├── src2
│ ├── class2.cc
│ └── class2.h
└── srcMain
└── main.cc
It should be mentioned that a more straight-forward way to do this is with the SConscript() function, specifying the variant_dir, but if your requirements dont allow you to do so, this example will work. The SCons man page has more info about the VariantDir() function. There you will also find the following:
Note that VariantDir() works most naturally with a subsidiary SConscript file.
Upvotes: 15
Reputation: 10357
To answer your first question: No, its not necessary to have a SConscript in every src sub-directory to be able to compile the files in that directory. Everything can be done from one single SConstruct.
Having said that, its often-times considered to be cleaner and better organized to have a SConscript in ever src sub-directory. Typically in this situation, the root SConstruct would setup things that are common to the entire project and orchestrate calling into the src sub-directories. Then, the SConstruct in each of the src subdirs would focus on the particulars of that subdir. I prefer this approach, as its more modular. Additionally, this would allow you to call the same src subdir SConstruct with different environments to compile different versions of the same code, like debug and release.
All of this can be done by creating an environment in the SConstruct, and then passing it to the sudirs with the SConscript() function. Here's an example:
SConstruct
env = Environment()
env.Append(CPPPATH = '/some/dir/common/to/all')
SConscript('src/subdirA/SConscript',
variant_dir = 'build/subdirA',
duplicate = 0,
exports = 'env')
SConscript('src/subdirB/SConscript',
variant_dir = 'build/subdirB',
duplicate = 0,
exports = 'env')
src/subdirA/SConscript
Import('env')
# If you need to add specific things to the env, then you should clone it,
# else the changes will be seen in other subdirs: clonedEnv = env.Clone()
# No need to specify the path to the source files if all source files are in
# the same dir as this SConscript.
env.Library(target='subdirA', source='fileA.cc')
src/subdirB/SConscript
Import('env')
# If you need to add specific things to the env, then you should clone it,
# else the changes will be seen in other subdirs: clonedEnv = env.Clone()
env.Library(target='subdirB', source='fileB.cc')
As for the last questions, I really dont understand what you're looking for, but using the option I explained above, the resulting compiled targets will always be placed in the VariantDir.
Upvotes: 2