I'm pretty new to SCons and noticed that CCCOMSTR and LINKCOMSTR will not work when I'm building a shared library in the SConscript.
Here is the simplified version of my SConstruct:
CFLAGS = ["-Wall", "-pedantic", "-std=c99"]
# building environment
env = Environment(CFLAGS = CFLAGS, CPPDEFINES = ["DEBUG"])
# checking dependencies
conf = env.Configure()
conf.CheckHeader("stdlib.h")
conf.CheckHeader("string.h")
conf.CheckLib("libdl")
env["CCCOMSTR"] = "Compiling $SOURCE ..."
env["LINKCOMSTR"] = "Linking $TARGET ..."
SConscript(dirs = ["lib1", "lib2"], exports=["env", "conf"], name = "SConscript")
# main function
env.Program(target = "prog", LIBS=["libdl"], source = Glob("*.c"))
and the library SConscript would look like:
Import("env", "conf")
env.SharedLibrary(target = "test1", source = Glob("*.c"))
My expectation is that the env["CCCOMSTR"] and env["LINKCOMSTR"] should be propagated via Import and displayed properly. This however isn't happening and I see a gcc/clang command instead.
Setting these variables in the SConscript does not make any difference either.
The output is as follows:
scons: Reading SConscript files ...
Checking for C header file stdlib.h... (cached) yes
Checking for C header file string.h... (cached) yes
Checking for C library libdl... (cached) yes
scons: done reading SConscript files.
scons: Building targets ...
Compiling log.c ...
Compiling main.c ...
clang -o lib1/test1.os -c -Wall -pedantic -std=c99 -g -fPIC -DDEBUG lib1/test1.c
clang -o lib1/libtest1.so -shared lib1/test1.os -ldl
clang -o lib2/test2.os -c -Wall -pedantic -std=c99 -g -fPIC -DDEBUG lib2/test2.c
clang -o lib2/libtest2.so -shared lib2/test2.os -ldl
Compiling xalloc.c ...
Linking prog ...
scons: done building targets.
Is it just a SCons bug or something that I am doing wrong here? Could not find much info about it in the net, hence asking here. :)
(SCONS versions that I've tried and that displayed the behaviour above are v2.1.0, v2.3.4)
After some research I found the answer and now it displays it properly:
...
env["SHCCCOMSTR"] = "SHCC $SOURCE"
env["SHLINKCOMSTR"] = "SHLINK $TARGET"
env["CCCOMSTR"] = "CC $SOURCE"
env["LINKCOMSTR"] = "LINK $TARGET"
...
I thought I had tried this before and it didn't work, but obviously something was wrong since it works now. So the output is as follows after the change (as expected):
...
CC log.c
CC main.c
SHCC lib1/test1.c
SHLINK lib1/libtest1.so
SHCC lib2/test2.c
SHLINK lib2/libtest2.so
CC util.c
CC xalloc.c
LINK prog
Oh well - SCons appears to work correctly and in fact rocks!
Related
I do not know gcc and c well. In my /home/pi/Desktop/intern/adis16227_generic directory I have following 5 files.
ADIS16227.c
ADIS16227.h
Communication.c
Communication.h
main.c
main.c
#include<stdio.h>
#include "Communication.h" // Communication definitions.
int main() {
printf("hello!!\n");
unsigned char status = 0;
status = SPI_Init(0, 1000000, 1, 1);
printf("%u", status);
return 0;
}
Run command:
$ sudo gcc -L /home/pi/Desktop/intern/adis16227_generic main.c -lCommunication
Error:
/usr/bin/ld: cannot find -lCommunication
collect2: error: ld returned 1 exit status
Question:
What I am missing here?
What do I need to run the code?
-l is for libraries, and you never built a library from your Communication.c. The simplest solution is just add Communication.c to your compiler command line.
For larger projects, compile each translation unit separately with the -c switch like this:
gcc -c -Wall -Wextra -pedantic -omain.o main.c
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
and so on ... (as a suggestion, I added some common warning options here, they help you spot errors)
The resulting .o files are object code. That's already compiled machine code, but with meta-information needed for a linker to link it with other object code into a complete executable.
Then link them all with one command:
gcc -oprogram main.o Communication.o
If you actually want a library from -- say -- Communication.c and ADIS16227.c, you could compile both to object code:
gcc -c -Wall -Wextra -pedantic -oCommunication.o Communication.c
gcc -c -Wall -Wextra -pedantic --oADIS16227.o ADIS16227.c
and then use ar to create a static library from them:
ar rcs libCommunication.a Communication.o ADIS16227.o
Then your initial compiler command would work (with the -lCommunication switch).
Final piece of advice: Never compile as root. This is completely unnecessary. So remove your sudo here.
those options:
-L /home/pi/Desktop/intern/adis16227_generic -lCommunication
suggest that the linker should find libCommunication.a (or .so) in the /home/pi/Desktop/intern/adis16227_generic directory.
But there are only sources in this directory. The linker won't build the sources of your "Communication" library for you.
So you could build the library and link with it:
gcc -c ADIS16227.c Communication.c
ar r libCommunication.a ADIS16227.o Communication.o
but maybe the fastest & quickest way to achieve a successful build would be:
sudo gcc -o main *.c
so it compiles all the files of the directory into the executable called main
Of course, it makes compilation times longer, but maybe it's not noticeable.
First move into the /home/pi/Desktop/intern/adis16227_generic directory:
cd /home/pi/Desktop/intern/adis16227_generic
Then, compile the source:
gcc ADIS16227.c Communication.c main.c -I .
You can now run your compiled program (called by default a.out):
./a.out
You have to compile separatedly files and then compile main with related obj file.
gcc -c Communication.c Communication.h
gcc main.c Communication.o -o main
I'm trying to compile code from a backtrace project https://code.google.com/p/backtrace-mingw/ which is written for MinGW, but using MinGW-w64.
My old install and fresh install of MinGW-w64 produce the same problem. Path is set in path variables, and also in command prompt:
C:\mingw-w64\i686-4.9.2-win32-sjlj-rt_v3-rev1\mingw32\bin
and C:\mingw-w64\i686-4.9.2-win32-sjlj-rt_v3-rev1\mingw32 although this one isn't needed.
This is the makefile of that project:
.PHONY: all clean
all : backtrace.dll test.exe
backtrace.dll : backtrace.c
gcc -O2 -shared -Wall -o $# $^ -lbfd -lintl -liberty -limagehlp
test.exe : test.c
gcc -g -Wall -o $# $^
clean :
-del -f backtrace.dll test.exe
When compiling I get the warning:
backtrace.c:23:17: fatal error: bfd.h: No such file or directory #include < bfd.h>`
Which is weird because that file exists in ../mingw32/include folder.
If I add this when compilind the dll: -IC:\mingw-w64\i686-4.9.2-win32-sjlj-rt_v3-rev1\mingw32\include it continues but stops at the directive: #error config.h must be included before this header and config.h is missing in MinGW-w64
Any ideas?
That path is definetely missing from gcc include paths in mingw. I don't know why. You have to add it yourself in any way you like: cmake recipe, autoconf recipe, CFLAGS, CPATH, gcc specs.
And, as far as I remember, it uses only HAVE_STRINGIZE macro from config.h and it is used only to define CONCAT4 macro, that's not used anywhere in bfd.h. So, it's safe to cheat a little and put
#define PACKAGE package
before including bfd.h
add this to the end of the compile statement:
-I./mingw32/include
so the whole compile statement would be:
gcc -g -Wall -o $# $^ -I./mingw32/include
so the compiler knows where to find the include files
when I want to try out nodejs module 'v8plus' that lead to only use C to write nodejs addons, I try its example file, but it tell errors that is lacking files.
could anyone tell me that how to get these lacking library files and install? thanks.
all error codes output in ubuntu bash shell:
$ make
/usr/bin/gcc -DBUILDING_NODE_EXTENSION -DMODULE=example -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DPIC -isystem /usr/local/bin/../include/node -I. -I/media/2/pro/v8plus/node_modules/v8plus -g -Wall -Wextra -Werror -fPIC -O2 -std=c99 -c -o example.o example.c
example.c:5:26: fatal error: sys/ccompile.h: No such file or directory
compilation terminated.
make: *** [example.o] Error 1
makefile all content:
V8PLUS = ..
include /media/2/pro/v8plus/node_modules/v8plus/Makefile.v8plus.defs
MODULE = example
MODULE_DIR = .
SRCS = \
example.c
ERRNO_JSON = errno.json
PREFIX_NODE = /opt/local
CC = /usr/bin/gcc
CXX = /usr/bin/g++
PREFIX_NODE := $(shell dirname bash -c 'hash node; hash -t node')/..
V8PLUS := $(shell $(PREFIX_NODE)/bin/node -e 'require("v8plus");')
include /media/2/pro/v8plus/node_modules/v8plus/Makefile.v8plus.targ
v8plus is only compatible with illumos distros as noted in the v8plus faq ("What systems can I use this on?"). So you won't be able to get it to compile on Windows, Linux, BSD, or OS X for example without some major changes.
My file stacking is as follows
dir1/
mylib.a
myheader.h
file.c
executable
dir2/
dependentfile.c // depends on functions in myheader.h implemented in mylib.a
I would like to link my static library file in my Makefile WITHOUT using its name, but just indicating its path. What I have is as follows:
Makefile for dir2/
CC = gcc
CFLAGS = -g -Wall $(INCLUDES)
INCLUDES = -I../dir1
LDFLAGS = -g -L../dir1
exec: dependentfile.o
dependentfile.o: dependentfile.c
Running 'make' just gives me a bunch of implicit declaration errors, and undefined references because it's not looking in the paths I have specified with -L and -I. My dependentfile.c also has the line
#include "myheader.h"
which it can't find.
How should I modify the makefile in order to make this work? I have tried multiple things, even specifying the lib file with -l and writing the complete path to no avail.
Any help is appreciated!
#
EDIT: Figured it out!
Turns out I was forgetting LDLIBS. So for everyone else, the makefile ended up looking like:
CC = gcc
CFLAGS = -g -Wall $(INCLUDES)
INCLUDES = -I../dir1
LDFLAGS = -g -L../dir1
LDLIBS = -lmylib (my actual file was named libmylib.a, forgo the "lib")
exec: dependentfile.o
dependentfile.o: dependentfile.c
I think you should use
#include "myheader.h"
Your header file name should be quoted.
I'm new to makefiles, so I apologize in advance if this is a silly question. Also I removed most variables from my makefile because they weren't working properly (gnu make tells me that $(myvar) should be completely replaces by the value of myvar, however the output of make was showing me that this was not happening), so I apologize for the ugliness and the more than 80 character lines.
acolibobj = acoLibInit acoGlobalDefs
acolibinterface: $(acolibobj).o
acoLibInit.o:
gcc -fPIC -g -c -Wall -I/usr/include/dc1394 -o acoLibinit.o acoCommands/acoLibInterface/acoLibInit.c
acoGlobalDefs.o:
gcc -fPIC -g -c -Wall -I/usr/include/dc1394 -o acoGlobalDefs.o acoCommands/acoLibInterface/acoGlobalDefs.c
When I run this makefile I get:
gcc -fPIC -g -c -Wall -I/usr/include/dc1394 -o acoLibinit.o acoCommands/acoLibInterface/acoLibInit.c
cc acoLibInit.o -o acoLibInit
gcc: acoLibInit.o: No such file or directory
gcc: no input files
make: *** [acoLibInit] Error 1
So far as I can tell, what's happening is that make is trying to compile AND link, even though I explicitly added the -c flag. When I run "gcc -fPIC -g -c..." myself (from bash), I do not get any problems at all. Why does make go on to try "cc acoLibInit.o -o acolibInit"?
make is trying to build acoLibInit. It probably has built-in rule that specifies "whatever" can be produced by linking "whatever.o", which is why you get that cc line.
This line:
acolibinterface: $(acolibobj).o
expands to:
acolibinterface: acoLibInit acoGlobalDefs.o
(note the absence of .o on the first dependency). This is why it's trying to link acoLibInit.
Try this:
acolibinterface: $(addsuffix .o,$(acolibobj))
if you want only the .o files as dependencies for that target.
$(acolibobj).o expands to acoLibInit acoGlobalDefs.o. Thus, you're really saying:
acolibinterface: acoLibInit acoGlobalDefs.o
Simply define acolibobj = acoLibInit.o acoGlobalDefs.o and use acolibinterface: $(acolibobj).