Scons - build order of Fortran files - build

Building modules in Fortran needs to be done in a specific order, e.g. if a file A.f needs module defined in B.f, then B.f needs to be compiled first. How can I impose such build order in Scons? If I provide it with a list of source files, it arranges them alphabetically (so A.f is compiled before B.f). I read about Requires() and Depends() functions, but wasn't able to get them to work for me.
I would be happy with just listing source files in order I need them compiled (so disabling reshuffling them in alphabetical order), but any other method would be welcomed as well.
As per Kyle's request, here's my Sconscript and a build log:
# Main program building script
Import('env')
PROGRAM = 'main.exe'
SRC_PREFIX = './src/'
SRC = [ 'array_1D_module.f',
'array_2D_module.f',
'array_3D_module.f',
'thomas_algorithm_module.f',
'histogram_module.f',
'histogram_computer_module.f',
'density_parameters_module.f',
'diffusion3D_aos_z_sub_solver_module.f',
'diffusion3D_aos_y_sub_solver_module.f',
'diffusion3D_aos_x_sub_solver_module.f',
'diffusion3D_aos_solver_module.f',
'nonlinear_diffusion_utilities_module.f',
'nonlinear_diffusion_parameters_module.f',
'derivative_magnitude_computer_module.f',
'nonlinear_diffusion_module.f',
'main_module.f',
'main.f' ]
# Attach prefix to each source file
for i in range( len(SRC) ) :
SRC[i] = SRC_PREFIX + SRC[i]
env.Program(target = PROGRAM, source = SRC)
This produced:
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
ifort -o src/array_1D_module.o -c src/array_1D_module.f
ifort -o src/array_2D_module.o -c src/array_2D_module.f
ifort -o src/array_3D_module.o -c src/array_3D_module.f
ifort -o src/density_parameters_module.o -c src/density_parameters_module.f
ifort -o src/derivative_magnitude_computer_module.o -c src/derivative_magnitude_computer_module.f
ifort -o src/diffusion3D_aos_solver_module.o -c src/diffusion3D_aos_solver_module.f
src/diffusion3D_aos_solver_module.f(7): error #7002: Error in opening the compiled module file. Check INCLUDE paths. [DIFFUSION3D_AOS_Z_SUB_SOLVER_MODULE]
use diffusion3D_aos_z_sub_solver_module, only :
------------^
So density_parameters_module.f was compiled before thomas_algorithm_module.f, even though it comes after it in my list.

Is your program (as suggested) using modules? There's a couple of gotchas there:
FORTRANMODDIR needs defining: See http://scons.tigris.org/ds/viewMessage.do?dsForumId=1272&dsMessageId=82725 for a discussion on that.
I found that having source files containing a mixture of module definitions and source code caused a certain amount of confusion.

Related

warning #10145 no action performed for file 'A.obj'

I am under windows (as the obj extension shows).
I have two valid .f90 files A.f90 and B.f90 (placed in the same folder) provided to me, where B.f90 uses A.f90, the code of B.f90 being :
module B
use A
! ... stuff
The code of A.f90 is
module A
! ... stuff
I compile A.f90 with :
ifort -c -fpp A.f90
Now I would like to compile B.f90 "while taking accound of" A.f90, that is, of its .obj file.
So I tried :
ifort -c B.f90 A.obj
which throws
ifort: warning #10145: no action performed for file 'A.obj'
at me.
Is the command
ifort -c B.f90
proper to compile B.f90 "while taking accound of" A.f90, that is, of its .obj file ?
I would like B.f90 it to be compiled "as A.f90 is", as in fact I have a third C.f90 (containing a use B) and that at the end I must run the command :
ifort -dll toto.dll A.o B.o C.o
to compile a dll while linking to all object files from A, B, C.
The information about module A that the compiler needs in order to compile file B.f90 is not in file A.f90 but in file A.mod (name of the module followed by .mod extension). The default is that .mod files are created in and read from the directory where ifort is run from. Therefore, if you compile files in the right order (as you are doing), and run ifort from the same directory when you compile all these files, it will have access to the previously compiled module files, and everything will work fine with simple commands such as
ifort -c B.f90
If, at compilation time, a compiler does not have access to the module file of a module that is used in the file currently compiled, an error will be isued and compilation will abort.

g++ does not produce debug symbols

I am learning linux, and my first step is to adapt my project for running on linux. Here is simple makefile (in educational purposes mostly), which generates out file:
#------------------------BUILD VARIABLES-----------------------------
# Directories, containing headers
INCLUDE_DIR = ../Include/
# Output directory which will contain output compiled file
OUTPUT_DIR = ../Bin/Debug/
SOURCES = EngineManager.cpp Geometry.cpp Main.cpp Model.cpp \
Shaders.cpp TGAImage.cpp
HEADERS = EngineManager.h Geometry.h Line.h Model.h Shaders.h \
TGAImage.h Triangle.h
#------------------------BUILD_RULES---------------------------------
TinyRenderBuilding : $(addprefix $(INCLUDE_DIR), $(HEADERS)) $(SOURCES)
mkdir -p $(OUTPUT_DIR)
g++ -std=c++14 -o $(OUTPUT_DIR)TinyRender.out -g -I$(INCLUDE_DIR) $(SOURCES)
I cannot understand, why does g++ not generate debug symbols? -g option is presented
To include debug symbols when compiling with g++ you need to pass the -g option.
In a make make file this usually means adding it to to CXXFLAGS.
Also make sure you pass the -g option when you create the executable: when you compile you turn .cpp files into .o files, when you do the linking you turn those .o files into your executable).
If you change the options before running make again be sure to run a make clean cause otherwise it won't get recompiled.
Finally, make sure that you do not have additional steps like strips command run on the executable (which would remove debugging symbols).
you can use
objdump --syms <executable-file>
to check if an executable have symbols.
when it doesn't have symbols it will say something like:
SYMBOL TABLE:
no symbols
(I'm no experto of C / C++ programming, I just run into this while I was trying to debug someone else code)
According to your makefile g++ should produce debug symbols (-g option is presented). To confirm this you can run file on resulting binary:
$ file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9fe588c18099ef418daf288931bb033cc287922e, with debug_info, not stripped
(Note with debug_info string in output)
I'm not entirely sure, but you can try -g or -ggdb.You can do some research on these. We were using these parameters to debug the C program with the gdb tool.

Scons: how to check file before compilation with commands which doesn't product any output file?

I work with project in which every object files is being built 3 times:
With newest g++ with lots of flags in order to find every possible errors and warnings
With clang in order to do as above and check style.
With g++ compatible with 3rdpart libraries (no newer version, but entire product is based of the libraries)
It works that way: if any object file should be recompiled: the steps 1, if success then 2, if success then 3 is being done. It is done with makefile, but I'm planning to use scons to do its. The problem is that in current solution object file from 1 and 2 is being saved into /dev/null.
I've tried something line this:
3 files in the same directory: hello.cc, Sconstruct, Sconscript
SConstruct
#!python
warningFlags = ' -Wall -Wextra -Werror' # and many more
env = Environment(CXX = 'g++-4.8', parse_flags = warningFlags, CPPPATH = '.')
builtObjects = env.SConscript('SConscript', variant_dir='built', duplicate=0, exports='env')
env.Program(target = 'hello', source = builtObjects)
SConscript
#!python
Import('env')
builtObjects = env.Object(source = 'hello.cc')
checkWithClang = env.Command('/dev/null', builtObjects, 'clang -o $TARGET -Wall -Werror')
env.Depends(checkWithClang, builtObjects)
Return('builtObjects')
The output from scons is:
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
scons: building associated VariantDir targets: built
g++-4.8 -o built/hello.o -c -Wall -Wextra -Werror -Ibuilt -I. hello.cc
g++-4.8 -o hello built/hello.o
scons: done building targets.
EDIT:
Is it possible to somehow check in scons:
if object file should be rebuilt?
Pseudo code:
src = 'hello.cc'
if shouldObjectFileBeRebuilt(src):
checkWithClang = env.Command('/dev/null', builtObjects, 'clang -o $TARGET -Wall -Werror')
builtObjects = env.Object(source = src)
env.Depends(checkWithClang, builtObjects)
try
src = "hello.cc"
builtObjects = env.Object(source = src)
checkWithClang = env.Command('/dev/null', src, 'clang -o $TARGET -Wall -Werror')
env.Depends(builtObjects, checkWithClang)
buildobjects represent '.o' files, so you should put '.c' files to clang
you want buildObjects to be built after clang objects - change the order
Still - building into /dev/null will probably break dependency tree, you might consider something like:
checkWithClang = env.Object(source = src, CC="clang", OBJPREFIX="clang-")
this will build all .c files with clang and store extra .o files, allowing scons to rebuild only what is necessarry

How to build and load shared library on rstudio for package that uses C/C++ files in src folder inside a subdirectory?

I have a R package that I'm working on that contains code written in C and C++ under the src folder. Currently, the package compiles and works on Rstudio as it follows the default directory structure. As the project builds, I want to be able to organize my code under src, within subfolders. Following directions from "Writing R extensions" - Compiling under sub-directories, I have made a folder called 'test'(/src/test) which now contains all my files(*.c, *.cpp, *.h) and modified my Makevars like so -
SOURCES_C = $(wildcard test/*.c)
SOURCES_CPP = $(wildcard test/*.cpp)
PKG_CPPFLAGS= -I${R_HOME}/include -I.
PKG_LIBS = -L${R_HOME}/lib
CXX_STD = CXX11
OBJECTS =$(SOURCES_CPP:.cpp=.o) $(SOURCES_C:.c=.o)
all : $(SHLIB)
#PKG_CFLAGS= -Wall
clean : rm -f *.o
I want to be able to compile the program in this state, where the C/C++ files are under subfolders inside src. Using the aforementioned Makevars -> the separate object files are being built from the test folder with the correct flags and compiler, for all C/CPP files. However, there are some discrepancies with the build command for the shared object. This is the log when compiling the files under src/test which fails with an undefined symbol error.
gcc -std=gnu99 -shared -L/usr/local/lib64 -o BioCro.so test/BBox.o test/Climate.o test/Compound.o test/Grid.o test/LeafOptics.o test/Maths.o test/Normal.o test/Point3D.o test/Ray.o test/Triangle.o test/Vector3D.o test/runFastTracer.o test/Assigncropcent.o test/AuxBioCro.o test/AuxCropGro.o test/AuxMaizeGro.o test/AuxcaneGro.o test/Auxcropcent.o test/AuxwillowGro.o test/BioCro.o test/CalculateBiogeochem.o test/Calculate_Soil_Layer_Temperature.o test/CanA.o test/CanAC_3D.o test/Century.o test/Copy_CropCent_To_DayCent_Structure.o test/Copy_SoilWater_BioCro_To_CropCent.o test/CropGro.o test/CropGro_c.o test/Filling_BioCro_SoilStructure.o test/assignManagement.o test/c3CanA.o test/c3EvapoTrans.o test/c3photo.o test/c4photo.o test/caneGro.o test/createNULLc3tree.o test/cropcent.o test/dailywillow.o test/denitrify.o test/diffusiv.o test/eC4photo.o test/getIdirIdiff.o test/getsoilprop.o test/leachdly.o test/maizeGro.o test/methane.o test/microclimate_for_3Dcanopy.o test/nitrify.o test/nox_pulse.o test/pi_funcs.o test/printcropcentoutput.o test/test_mainC.o test/tgmodel.o test/tracegas.o test/update_3Dcanopy_structure.o test/wfps.o test/willowCent.o test/willowGro.o -L/usr/local/R-3.1.0/lib64/R/lib -L/usr/local/R-3.1.0/lib64/R/lib -lR
installing to /home/vashist1/R/x86_64-unknown-linux-gnu-library/3.1/BioCro/
** R
** data
** inst
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** installing vignettes
** testing if installed package can be loaded
Error in dyn.load(file, DLLpath = DLLpath, ...) :
unable to load shared object '/home/vashist1/R/x86_64-unknown-linux-gnu-library/3.1/BioCro/libs/BioCro.so':
/home/vashist1/R/x86_64-unknown-linux-gnu-library/3.1/BioCro/libs/BioCro.so:
undefined symbol: _ZTVN10__cxxabiv117__class_type_infoE
Error: loading failed
Compared with the successful log which builds successfully!
g++ -shared -L/usr/local/lib64 -o BioCro.so Assigncropcent.o AuxBioCro.o AuxCropGro.o AuxMaizeGro.o AuxcaneGro.o Auxcropcent.o AuxwillowGro.o BBox.o BioCro.o CalculateBiogeochem.o Calculate_Soil_Layer_Temperature.o CanA.o CanAC_3D.o Century.o Climate.o Compound.o Copy_CropCent_To_DayCent_Structure.o Copy_SoilWater_BioCro_To_CropCent.o CropGro.o CropGro_c.o Filling_BioCro_SoilStructure.o Grid.o LeafOptics.o Maths.o Normal.o Point3D.o Ray.o Triangle.o Vector3D.o assignManagement.o c3CanA.o c3EvapoTrans.o c3photo.o c4photo.o caneGro.o createNULLc3tree.o cropcent.o dailywillow.o denitrify.o diffusiv.o eC4photo.o getIdirIdiff.o getsoilprop.o leachdly.o maizeGro.o methane.o microclimate_for_3Dcanopy.o nitrify.o nox_pulse.o pi_funcs.o printcropcentoutput.o runFastTracer.o test_mainC.o tgmodel.o tracegas.o update_3Dcanopy_structure.o wfps.o willowCent.o willowGro.o -L/usr/local/R-3.1.0/lib64/R/lib -lR
installing to /home/vashist1/R/x86_64-unknown-linux-gnu-library/3.1/BioCro/libs
1) The shared object compiles using g++ under default conditions, whereas under subdirectory conditions the compiler used is gcc. Can I change that behaviour via Makevars?
2) Further research allowed me to find that the undefined symbol error is a linking error fixed by the -L/-l flag. However, the -L flag is the same for both build commands. Is there any other library I am failing to link which is linked by default?
I ran into the same issue. Looking at the example of the RSiena package mentioned as an example in "Writing R Extensions" section 1.2.1.3 I noticed that that package still has some .cpp files not in a subdirectory. So I added a dummy.cpp file in src/ with the following contents:
void dummy (void)
{
}
After this g++ was correctly used for the linking step and the .so file was created as expected.
In my case it turns out that I don't need to change the Makevars files as I first mentioned in my answer. Even without the change below (so only having the dummy.cpp file present in src/) linking is done correctly.
I'll leave it in in case it may help someone else with a (slightly) different setup.
And add the corresponding .o file in the list of $(OBJECTS) variable in the Makevars file:
OBJECTS = $(SOURCES:.cpp=.o) dummy.o

gcov on larger projects (static libraries, ...)

I'm working on larger project which has the following directory layout:
Source
MyA
aa.cpp
ab.cpp
ac.cpp
MyB
ba.cpp
bb.cpp
bc.cpp
MyTest
testaa.cpp
testab.cpp
testac.cpp
testba.cpp
testbb.cpp
testbc.cpp
main.cpp
Build
MyA
aa.o
ab.o
ac.o
libMyA.a (static library)
MyB
ba.o
bb.o
bc.o
libMyB.a (static library)
MyTest
testaa.o
testab.o
testac.o
testba.o
testbb.o
testbc.o
MyTest (executable)
After compiling with -fprofile-arcs -ftest-coverage I execute the MyTest application inside the Build/MyTest directory. As expected there are *.gcno and *.gcda files inside the Build directory. After running gcov inside the MyTest directory different *.gcov files are produced but unfortunately not for everything inside MyA and MyB, although every function is called inside this two libraries. Tried different options but somehow I'm unable to create useful (means correct) *.gcov files with this layout.
If I copy every cpp inside one directory and repeat the steps everything works as expected and the coverage analysis is perfect.
You must specify source files as absolute paths to g++/gcc. Don't use relative paths with ".." or like "foo/bar.cpp", else you'll get errors like "geninfo: WARNING: no data found for XXXX".
Don't include any header files on the command line to g++/gcc. Else you'll get "stamp mismatch with graph file" errors.
So, following should work when having multiple directories:
g++ --coverage -DDEBUG -g3 heyo.cpp /app/helper/blah.cpp /app/libfoo/foo.cpp -o program
./program
lcov --directory . --capture --output-file app.info
genhtml --output-directory cov_htmp app.info
Or, if you're in a Makefile that uses relative paths already, it's convenient to use:
g++ --coverage -DDEBUG -g3 $(abspath heyo.cpp helper/blah.cpp ../foo/bar/baz.cpp) -o program
To be able to keep your directory structure, you need to run gcov once inside each source file folder, but use the -o option to tell gcov where the data files are.
I think it should be like this:
gcov -o ../../Build/MyA *.cpp
I have a project with a similar source file structure, but I let the compiler dump object files etc into the source folders. I then run gcov multiple times from the root folder, once for each source file, but I specify the relative path of the source file and use the -o option to specify the relative folder like this:
gcov -o Source/MyA Source/MyA/aa.cpp
If you performed your product or application testing thoroughly and manually and spent lot of effort on it. If your objective is to get code coverage report using lcov and gcov but by mistake deleted gcno files. You can regenerate gcno files by recompiling the code but it will be generated with new timestamp and gcov reports error saying "stamp mismatch with graph file" and no code coverage report will be generated. This will result in all your testing effort getting wasted.
There is a shortcut to still generate the code coverage report. This is just a workaround and should not be relied upon all the time. Its recommended to preserve *.gcno files till your testing completes.
Note down your gcc version(gcc -v) and download its source code from one of the mirror sites
Eg - ftp://gd.tuwien.ac.at/gnu/sourceware/gcc/releases/gcc-4.4.6/gcc-4.4.6.tar.bz2
After extracting downloaded file, gcc the folder structure will be as follows
gcc-4.4.6
gcc-4.4.6/gcc
If you directly go inside gcc-4.4.6/gcc and try to do ./configure and compile(make) from there then you will encounter below problem
build/genmodes -h > tmp-modes.h
/bin/sh: build/genmodes: No such file or directory
Solution is do ./configure and make from gcc-4.4.6 and no errors will be shown related to genmodes. This will compile all modules including gcc. You may have to install mpfr and gmp modules which are needed by gcc if any error shown by ./configure
goto gcc-4.4.6/gcc/gcov.c and comment below lines and then recompile with above command
/* if (tag != bbg_stamp)
{
fnotice (stderr, "%s:stamp mismatch with graph file\n", da_file_name);
goto cleanup;
}*/
Example path of new gcov binary after compilation is gcc-4.4.6/host-x86_64-unknown-linux-gnu/gcc/gcov
Place this binary in /usr/bin and regenerate code coverage report with command as shown in below example
lcov --capture --directory ./ --output-file coverage.info ; genhtml coverage.info --output-directory /var/www/html/coverage
Now you should not get "stamp mismatch with graph file" error and you will get code coverage report properly