Scons custom dependency scanner not called for .cpp files - scons

I have a scons project directory containing following files:
dep.txt
main.cpp
SConstruct
content of SConstruct:
env = Environment()
def f_scan(node, env, path):
print("[.] Scanner invoked. -> %s" % str(node))
return env.File(["dep.txt"])
fscan = Scanner(function = f_scan, skeys = ['.o', '.cpp'])
env.Append(SCANNERS = fscan)
env.Program('main', ['main.cpp'])
content of main.cpp:
#include <iostream>
using namespace std;
int main(){
cout << 1 << endl;
return 0;
}
content in dep.txt does not have any specific meaning.
scons -Q output(if dep.txt was changed after last build):
[.] Scanner invoked. -> main.o
g++ -o main main.o
scons -Q output(if dep.txt was not changed after last build):
[.] Scanner invoked. -> main.o
scons: `.' is up to date.
I am trying to implement a custom scanner for .cpp files. I want to add extra dependencies for all .cpp files on top of one that is detected by inbuilt Scanner. But I notice that scanner never called on .cpp files. However, it gets called correctly for .o files.

From the manpage: https://scons.org/doc/production/HTML/scons-man.html#scanner_objects
Note that scons has a global SourceFileScanner object that is used by
the Object, SharedObject and StaticObject builders to decide which
scanner should be used for different file extensions. You can use the
SourceFileScanner.add_scanner() method to add your own Scanner object
to the SCons infrastructure that builds target programs or libraries
from a list of source files of different types:
So if you change to:
env = Environment(CPPPATH=['.'])
def f_scan(node, env, path):
print("[.] Scanner invoked. -> %s" % str(node))
return env.File(["dep.txt"])
fscan = Scanner(f_scan)
SourceFileScanner.add_scanner('.cpp', fscan)
SourceFileScanner.add_scanner('.o', fscan)
env.Program('main', ['main.cpp'])
Note that you are not adding to the scanners applied to .cpp and .o, you are replacing them.
So if I create an x.h and change main.cpp to:
#include <iostream>
#include "x.h"
using namespace std;
int main(){
cout << 1 << endl;
return 0;
}
You will see this:
% python ~/devel/scons/git/as_scons/scripts/scons.py --tree=prune
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
[.] Scanner invoked. -> main.o
[.] Scanner invoked. -> main.cpp
g++ -o main.o -c -I. main.cpp
[.] Scanner invoked. -> main.o
g++ -o main main.o
+-.
+-SConstruct
+-dep.txt
+-main
| +-main.o
| | +-main.cpp
| | +-dep.txt
| | +-/usr/bin/g++
| +-dep.txt
| +-/usr/bin/g++
+-main.cpp
+-[main.o]
scons: done building targets.
Whereas without your custom scanner:
% python ~/devel/scons/git/as_scons/scripts/scons.py --tree=prune
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o main main.o
+-.
+-SConstruct
+-main
| +-main.o
| | +-main.cpp
| | +-x.h
| | +-/usr/bin/g++
| +-/usr/bin/g++
+-main.cpp
+-[main.o]
+-x.h
scons: done building targets.
So what you likely want is to still call the existing scanner and add your file to it:
env = Environment(CPPPATH=['.'])
# get existing .cpp scanner
origin_cpp_scanner = SourceFileScanner.function['.cpp']
def f_scan(node, env, path):
filename = str(node)
print("[.] Scanner invoked. -> %s" % filename)
if filename.endswith('.cpp'):
current_files = origin_cpp_scanner(node, env, path)
else:
current_files = []
print("Files:%s"%[str(f) for f in current_files])
return current_files + env.File(["dep.txt"])
fscan = Scanner(f_scan)
SourceFileScanner.add_scanner('.cpp', fscan)
SourceFileScanner.add_scanner('.o', fscan)
env.Program('main', ['main.cpp'])
Which then yields:
% python ~/devel/scons/git/as_scons/scripts/scons.py --tree=prune
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
[.] Scanner invoked. -> main.o
Files:[]
[.] Scanner invoked. -> main.cpp
Files:['x.h']
g++ -o main.o -c -I. main.cpp
[.] Scanner invoked. -> main.o
Files:[]
g++ -o main main.o
+-.
+-SConstruct
+-dep.txt
+-main
| +-main.o
| | +-main.cpp
| | +-x.h
| | +-dep.txt
| | +-/usr/bin/g++
| +-dep.txt
| +-/usr/bin/g++
+-main.cpp
+-[main.o]
+-x.h
scons: done building targets.

Related

SCons does not find file it should build itself

I have a simple SConstruct file to build the google test library with MinGW:
env = Environment(platform='posix') # necessary to use gcc and not MS
env.Append(CPPPATH=['googletest/'])
env.Append(CCFLAGS=[('-isystem', 'googletest/include/'), '-pthread'])
obj = env.Object(source='googletest/src/gtest-all.cc')
# linking skipped due to error search
# env.Append(LINKFLAGS=['-rv'])
# bin = env.StaticLibrary(target='libgtest', source=[obj])
The script resides in the main googletest\ folder. When running it - with or without linking - the output is this:
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o googletest\src\gtest-all.o -c -isystem googletest/include/ -pthread -Igoogletest googletest\src\gtest-all.cc
scons: *** [googletest\src\gtest-all.o] The system cannot find the file specified
+-.
+-googletest
| +-googletest\src
| +-googletest\src\gtest-all.cc
| +-googletest\src\gtest-all.o
| | +-googletest\src\gtest-all.cc
| | +-googletest\src\gtest-death-test.cc
| | +-googletest\src\gtest-filepath.cc
| | +-googletest\src\gtest-port.cc
| | +-googletest\src\gtest-printers.cc
| | +-googletest\src\gtest-test-part.cc
| | +-googletest\src\gtest-typed-test.cc
| | +-googletest\src\gtest.cc
| | +-googletest\src\gtest-internal-inl.h
| +-googletest\src\gtest-death-test.cc
| +-googletest\src\gtest-filepath.cc
| +-googletest\src\gtest-internal-inl.h
| +-googletest\src\gtest-port.cc
| +-googletest\src\gtest-printers.cc
| +-googletest\src\gtest-test-part.cc
| +-googletest\src\gtest-typed-test.cc
| +-googletest\src\gtest.cc
| +-googletest\src\libgtest-all.a
| +-googletest\src\gtest-all.o
| +-googletest\src\gtest-all.cc
| +-googletest\src\gtest-death-test.cc
| +-googletest\src\gtest-filepath.cc
| +-googletest\src\gtest-port.cc
| +-googletest\src\gtest-printers.cc
| +-googletest\src\gtest-test-part.cc
| +-googletest\src\gtest-typed-test.cc
| +-googletest\src\gtest.cc
| +-googletest\src\gtest-internal-inl.h
+-SConstruct
scons: building terminated because of errors.
I also tried to build the library in one line: env.StaticLibrary(source='googletest/src/gtest-all.cc') - the result is the same.
Just executing the actuall g++ call gives me the object file I want.
What confuses me is that SCons should see the object file as an artifact it creates itself. I wondering why it tries to use it before it is finished. So what am I missing here? How can I make SCons wait until the compiling is done?
BTW: I just have some experience in using SCons and and did tweak a script once a while - but I do not really have profound knowledger about it.
Versions used: SCons 3.0.1, Python 3.6.3, MinGW 7.3.0
Does this work?
env = Environment(tools=['mingw','gnulink','ar']) # You should specify the tools
env.Append(CPPPATH=['googletest/'])
env.Append(CCFLAGS=[('-isystem', 'googletest/include/'), '-pthread'])
obj = env.Object(source='googletest/src/gtest-all.cc')
# linking skipped due to error search
# env.Append(LINKFLAGS=['-rv'])
# bin = env.StaticLibrary(target='libgtest', source=[obj])

How to build when multiple source files in rootfs in embedded linux?

I have a simple c application
Ctest.c file
#include <stdio.h>
#include "new.h"
#include "new.c"
int main()
{
switching();
return 0;
}
and i have those new.c and new.h files.
new.h file as
void switching();
and my new.c file as
void switching(){
char grade ='B';
switch(grade){
case 'A':
printf("Excellent\n");
break;
case 'B':
printf("Super\n");
break;
case 'C':
printf("Well done\n");
break;
case 'D':
printf("You passed\n");
break;
case 'F':
printf("Better try again");
break;
default:
printf("invalid grade");
break;
}
printf("your grade is %c \n",grade);
}
When i try to use build commands in my embedded linux tool for compiling and generating a binary , building is failed and here is my changed make file for the application on rootfs.
make file for the app Ctest:
APP = Ctest
# Add any other object files to this list below
APP_OBJS = Ctest.o
APP_OBJS += new.o
all: build
build: $(APP)
$(APP): $(APP_OBJS)
$(CC) $(LDFLAGS) -o $# $(APP_OBJS) $(LDLIBS)
Here is my error log during compile time
DEBUG: Executing shell function do_compile
NOTE: make -j 4
ERROR: oe_runmake failed
aarch64-xilinx-linux-gcc --sysroot=/home/janani/projects/peta2017.1-zcu102/zcu102/petlnx_zcu102/build/tmp/sysroots/plnx_aarch64 -O2 -pipe -g -feliminate-unused-debug-types -fdebug-prefix-map=/home/janani/projects/peta2017.1-zcu102/zcu102/petlnx_zcu102/build/tmp/work/aarch64-xilinx-linux/Ctest/1.0-r0=/usr/src/debug/Ctest/1.0-r0 -fdebug-prefix-map=/home/janani/projects/peta2017.1-zcu102/zcu102/petlnx_zcu102/build/tmp/sysroots/x86_64-linux= -fdebug-prefix-map=/home/janani/projects/peta2017.1-zcu102/zcu102/petlnx_zcu102/build/tmp/sysroots/plnx_aarch64= -c -o Ctest.o Ctest.c
aarch64-xilinx-linux-gcc --sysroot=/home/janani/projects/peta2017.1-zcu102/zcu102/petlnx_zcu102/build/tmp/sysroots/plnx_aarch64 -O2 -pipe -g -feliminate-unused-debug-types -fdebug-prefix-map=/home/janani/projects/peta2017.1-zcu102/zcu102/petlnx_zcu102/build/tmp/work/aarch64-xilinx-linux/Ctest/1.0-r0=/usr/src/debug/Ctest/1.0-r0 -fdebug-prefix-map=/home/janani/projects/peta2017.1-zcu102/zcu102/petlnx_zcu102/build/tmp/sysroots/x86_64-linux= -fdebug-prefix-map=/home/janani/projects/peta2017.1-zcu102/zcu102/petlnx_zcu102/build/tmp/sysroots/plnx_aarch64= -c -o new.o new.c
new.c: In function 'switching':
new.c:5:13: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
printf("Excellent\n");
^~~~~~
new.c:5:13: warning: incompatible implicit declaration of built-in function 'printf'
new.c:5:13: note: include '<stdio.h>' or provide a declaration of 'printf'
new.c:24:5: warning: incompatible implicit declaration of built-in function 'printf'
printf("your grade is %c \n",grade);
^~~~~~
new.c:24:5: note: include '<stdio.h>' or provide a declaration of 'printf'
Ctest.c:33:17: fatal error: new.h: No such file or directory
#include "new.h"
^
compilation terminated.
make: *** [<builtin>: Ctest.o] Error 1
make: *** Waiting for unfinished jobs....
ERROR: Function failed: do_compile (log file is located at /home/janani/projects/peta2017.1-zcu102/zcu102/petlnx_zcu102/build/tmp/work/aarch64-xilinx-linux/Ctest/1.0-r0/temp/log.do_compile.19737)
i understood that i need to do changes in the make file or bitbake file that build the application ie., Ctest.bb file If so what are the changes? And I am using petalinux 2017.1
the bitbake file of the application is
#
# This file is the Ctest recipe.
#
SUMMARY = "Simple Ctest application"
SECTION = "PETALINUX/apps"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://Ctest.c \
file://new.c \
file://Makefile \
"
S = "${WORKDIR}"
do_compile() {
oe_runmake
}
do_install() {
install -d ${D}${bindir}
install -m 0755 Ctest ${D}${bindir}
install -m 0755 new ${D}${bindir}
}
How can i give new.h file into the make file or do i need to change the bitbake file?
Your Ctest.c file includes new.c so you should not be trying to build new.o at all. Remove the line
APP_OBJS += new.o
and
install -m 0755 new ${D}${bindir}
You are not providing the new.h file in your SRC_URI. Change it to
SRC_URI = "file://Ctest.c \
file://new.c \
file://new.h \
file://Makefile \
"

OpenMPI runtime error : Hello World

I'm able to successfully compile my code when I execute the make command. However, when I run the code as:
mpirun -np 4 test
The error generated is:
-------------------------------------------------------
Primary job terminated normally, but 1 process returned
a non-zero exit code.. Per user-direction, the job has been aborted.
-------------------------------------------------------
--------------------------------------------------------------------------
mpirun detected that one or more processes exited with non-zero status, thus causing
the job to be terminated. The first process to do so was:
Process name: [[63067,1],2]
Exit code: 1
--------------------------------------------------------------------------
I have no multiple mpi installations so I don't expect there to be a problem.
I've been having trouble with my Hello World OpenMPI program. My main file is :
#include <iostream>
#include "mpi.h"
using namespace std;
int main(int argc, const char * argv[]) {
MPI_Init(NULL, NULL);
int size, rank;
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
cout << "The number of spawned processes are " << size << "And this is the process " << rank;
MPI_Finalize();
return 0;
}
My makefile is:
# Compiler
CXX = mpic++
# Compiler flags
CFLAGS = -Wall -lm
# Header and Library Paths
INCLUDE = -I/usr/local/include -I/usr/local/lib -I..
LIBRARY_INCLUDE = -L/usr/local/lib
LIBRARIES = -l mpi
# the build target executable
TARGET = test
all: $(TARGET)
$(TARGET): main.cpp
$(CXX) $(CFLAGS) -o $(TARGET) main.cpp $(INCLUDE) $(LIBRARY_INCLUDE) $(LIBRARIES)
clean:
rm $(TARGET)
The output of: mpic++ --version is:
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
And that for mpirun --version is:
mpirun (Open MPI) 2.1.1
Report bugs to http://www.open-mpi.org/community/help/
What could be causing the issue?
This is now resolved. It turns out that I have to execute with
mpirun -np 4 ./test
Ref: users-request#lists.open-mpi.org

Linking cuda object file

I have one .cu file that contains my cuda kernel, and a wrapper function that calls the kernel. I have a bunch of .c files as well, one of which contains the main function. One of these .c files calls the wrapper function from the .cu to invoke the kernel.
I compile these files as follows:
LIBS=-lcuda -lcudart
LIBDIR=-L/usr/local/cuda/lib64
CFLAGS = -g -c -Wall -Iinclude -Ioflib
NVCCFLAGS =-g -c -Iinclude -Ioflib
CFLAGSEXE =-g -O2 -Wall -Iinclude -Ioflib
CC=gcc
NVCC=nvcc
objects := $(patsubst oflib/%.c,oflib/%.o,$(wildcard oflib/*.c))
table-hash-gpu.o: table-hash.cu table-hash.h
$(NVCC) $(NVCCFLAGS) table-hash.cu -o table-hash-gpu.o
main: main.c $(objects) table-hash-gpu.o
$(CC) $(CFLAGSEXE) $(objects) table-hash-gpu.o -o udatapath udatapath.c $(LIBS) $(LIBDIR)
So far everything is fine. table-hash-gpu.cu calls a function from one of the .c files. When linking for main, I get the error that the function is not present. Can someone please tell me what is going on?
nvcc compiles both device and host code using the host C++ compiler, which implies name mangling. If you need to call a function compiled with a C compiler in C++, you must tell the C++ compiler that it uses C calling conventions. I presume that the errors you are seeing are analogous to this:
$ cat cfunc.c
float adder(float a, float b, float c)
{
return a + 2.f*b + 3.f*c;
}
$ cat cumain.cu
#include <cstdio>
float adder(float, float, float);
int main(void)
{
float result = adder(1.f, 2.f, 3.f);
printf("%f\n", result);
return 0;
}
$ gcc -m32 -c cfunc.c
$ nvcc -o app cumain.cu cfunc.o
Undefined symbols:
"adder(float, float, float)", referenced from:
_main in tmpxft_0000b928_00000000-13_cumain.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Here we have code compiled with nvcc (so the host C++ compiler) trying to call a C function and getting a link error, because the C++ code expects a mangled name for adder in the supplied object file. If the main is changed like this:
$ cat cumain.cu
#include <cstdio>
extern "C" float adder(float, float, float);
int main(void)
{
float result = adder(1.f, 2.f, 3.f);
printf("%f\n", result);
return 0;
}
$ nvcc -o app cumain.cu cfunc.o
$ ./app
14.000000
It works. Using extern "C" to qualify the declaration of the function to the C++ compiler, it will not use C++ mangling and linkage rules when referencing adder and the resulting code links correctly.

Why I'm not getting "Multiple definition" error from the g++?

I tried to link my executable program with 2 static libraries using g++. The 2 static libraries have the same function name. I'm expecting a "multiple definition" linking error from the linker, but I did not received. Can anyone help to explain why is this so?
staticLibA.h
#ifndef _STATIC_LIBA_HEADER
#define _STATIC_LIBA_HEADER
int hello(void);
#endif
staticLibA.cpp
#include "staticLibA.h"
int hello(void)
{
printf("\nI'm in staticLibA\n");
return 0;
}
output:
g++ -c -Wall -fPIC -m32 -o staticLibA.o staticLibA.cpp
ar -cvq ../libstaticLibA.a staticLibA.o
a - staticLibA.o
staticLibB.h
#ifndef _STATIC_LIBB_HEADER
#define _STATIC_LIBB_HEADER
int hello(void);
#endif
staticLibB.cpp
#include "staticLibB.h"
int hello(void)
{
printf("\nI'm in staticLibB\n");
return 0;
}
output:
g++ -c -Wall -fPIC -m32 -o staticLibB.o staticLibB.cpp
ar -cvq ../libstaticLibB.a staticLibB.o
a - staticLibB.o
main.cpp
extern int hello(void);
int main(void)
{
hello();
return 0;
}
output:
g++ -c -o main.o main.cpp
g++ -o multipleLibsTest main.o -L. -lstaticLibA -lstaticLibB -lstaticLibC -ldl -lpthread -lrt
The linker does not look at staticLibB, because by the time staticLibA is linked, there are no unfulfilled dependencies.
That's an easy one. An object is only pulled out of a library if the symbol referenced hasn't already been defined. Only one of the hellos are pulled (from A). You'd get errors if you linked with the .o files.
When the linker tries to link main.o into multipleLibsTest and sees that hello() is unresolved, it starts searching the libraries in the order given on the command line. It will find the definition of hello() in staticLibA and will terminate the search.
It will not look in staticLibB or staticLibC at all.
If staticLibB.o contained another symbol not in staticLibA and that was pulled into the final executable, you then get a multiple definition of hello error, as individual .o files are pulled out of the library and two of them would have hello(). Reversing the order of staticLibA and staticLibB on the link command line would then make that error go away.

Resources