How is the CPU symbol resolved in this C sample code? - c

I ran into the following code in location.c for the apache jsvc java daemon.
char *location_jvm_cfg[] = {
"$JAVA_HOME/jre/lib/jvm.cfg", /* JDK */
"$JAVA_HOME/lib/jvm.cfg", /* JRE */
"$JAVA_HOME/jre/lib/" CPU "/jvm.cfg", /* JDK */
"$JAVA_HOME/lib/" CPU "/jvm.cfg", /* JRE */
NULL,
};
I grepped through the source code to find out the CPU macro is expanded in the code "$JAVA_HOME/jre/lib/" CPU "/jvm.cfg" but could not find such a MACRO defined.
I am not really sure if CPU is a C Macro or some other thing that is being configured the autoconf tools.
how is the above CPU value being substituted for the real CPU value?
The problem I am facing is that when I build jsvc on Solaris with CFLAGS and LDFLAGS set to -m64 the generated 64 bit solaris binary tries to load the jvm .so files from $JAVA_HOME/jre/lib/sparc/jvm.cfg instead of $JAVA_HOME/jre/lib/sparcv9/jvm.cfg
UPDATE
Running ./configure that ships with JSVC with the following command line does the right thing
configure --with-java=/path/to/jdk1.7.0_45 --host=sparcv9-sun-solaris2.10 CFLAGS="-m64" LDFLAGS="-m64"
the extra --host=sparcv9-sun-solaris2.10 causes the generated gcc command to be
gcc -m64 -DOS_SOLARIS -DDSO_DLFCN -DCPU=\"sparcv9\" -Wall -Wstrict-prototypes
Instead of
gcc -m64 -DOS_SOLARIS -DDSO_DLFCN -DCPU=\"sparc\" -Wall -Wstrict-prototypes
which is what was causing the generated 64 bit jsvc binary to try to link against the 32 bit so files instead of the 64 bit so files.

It absolutely must be a preprocessor define. Nothing else would work in that code.
For making configure use different CPUs, it may be possible that the configure script takes a configuration triplet. That might look like 'i686-unknown-gnu-linux'
Apparently configure.guess does the work of figuring this out. If you specify one of these triplets (quadruplets?) on the configure command line it might think it is building in a cross-compiler, but it should work.

The generated configure script adds -DCPU to CFLAGS, based on the value of configure --host, which defaults to configure --build, which defaults to a guessed value.

Related

stdio.h and FPU errors in Neovim using clangd LSP

I have a stm32f103 project that is initialized using stm32cubemx and I'm using neovim for editing and arm-none-eabi-gcc for compilation of code (whit auto-generated makefile).
I also have installed clangd LSP and also bear to generate compile_commands.json file. Everyting works fine except that there's two errors:
stdio.h file not found
Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)
I looked at core_cm3.h file and __FPU_USED is disabled, which is exactly what clang says.
/** __FPU_USED indicates whether an FPU is used or not.
This core does not support an FPU at all
*/
#define __FPU_USED 0U
But I couldn't find any line in my makefile flags that enables the FPU for compilation.
# fpu
# NONE for Cortex-M0/M0+/M3
# float-abi
# mcu
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
I also commented out $(FPU) and $(FLOAT-ABI), but the error still exists.
Although I can compile the project without any problems (because gcc has no complaints), but these errors are kind of on my nerve.
Is there a way to fix these errors? Or is there any gcc-based LSPs to use instead of clangd?
There's also ccls on neovim's LSP list but I was unable to install it.
s there a way to fix these errors?
https://clangd.llvm.org/config#files You can:
create clangd configuration file
specify -sysroot command to specify the location of your buildchain (/usr/arm-none-eabi/ on my system)
and other needed options (-isysroot -nostdlib etc.) if you use them.
I would advise anyway to move CMake and generate compile_command.json anyway.
is there any gcc-based LSPs to use instead of clangd?
I am not aware of any.

GDB cannot step into function, OZone can

I have a setup like this:
GDB from "GNU Arm Embedded Toolchain" 10.3-2021.10
GDB server from "Segger JLink" 7.54d
JLink Ultra+ connected to my PC and my embedded device
Arm Compiler 6.15
I'm having problems stepping into a certain function from a C module (let's call it "F1"). When trying, I get the error message
Single stepping until exit from function "F1", which has no line number information.
If I use Segger Ozone, with the same .elf file, stepping into "F1" works fine.
I've tried to narrow down the problem and have the following observations:
A single line of code from the C module holding "F1" makes the difference. If I remove this line, it works. This line is a simple incrementation (++) of a static uint32_t variable and it is in a separate function (i.e. not "F1").
If I don't link with "--inline" option, it stops working - even with the "fix" in (1)
All source files (a mix of C and C++ files) are compiled with -g option.
I may try to reproduce it in a much smaller context which I could share here but until then, I'm hoping for some hints.
Anything is appreciated.
[Update 2021-11-10] Tried with older/newer versions of "GNU Arm Embedded Toolchain" as well as "Segger JLink". Same problem.
[Update 2021-11-10] Compiler/linker command used:
armclang -g --target=arm-arm-none-eabi -mcpu=cortex-m33 -mfloat-abi=soft -MMD -Werror -D__STDC_LIMIT_MACROS -I<my_include_paths>
armlink --inline --info=sizes --info=veneers --info=unused --info=totals --map --symbols --scatter=<my_scatter_file> --list=list.txt

How to implement Erlang Driver As Default efficient Implementation

Erlang Run-Time System (ERTS) have a few drivers written in C language that used to interact with the OS or to access low-level resources, In my knowledge the ERTS compile these drivers at boot time to get ready for loading from Erlang code, the driver inet_drv.c is one of these drivers and it's used to handle networking tasks like creating sockets and listening or accepting new incoming connections.
I wanted to test this driver manually to get a general view of the default behaviour of the ERTS and to know how to implement drivers efficiently in the future, I tracked the Erlang Manual Reference to implement drivers that said: first write and compile the driver by an OS C Language Compiler, second load the driver from erlang code using erl_ddll module, finally link to the driver by a spawned Erlang process, so this is very simple and easy.
So I tried these steps with the driver inet_drv.c, I searched for it and tried to compile it with Clang Compiler which is the Default C Compiler of FreeBSD System :
cc inet_drv.c
after that there was an error saying that the file erl_driver.h is not defined, this header file is used in the driver's code as an included file (#include<erl_driver.h>) so I searched for it and add it's directory path to the cc command using the -I option to get the compiler search for the included file in this directory and I recompile it :
cc inet_drv.c -I/usr/ports....
after that, there was be another undefined file so I did the same thing for 5 or 6 times and finally, I add all needed paths for included files and the result is this command :
cc inet_drv.c
-I/usr/ports/lang/erlang/work/otp-OTP-21.3.8.18/erts/emulator/beam
-I/usr/local/lib/erlang/usr/include
-I/usr/ports/lang/erlang/work/otp-OTP-21.3.8.18/erts/emulator/sys/unix
-I/usr/ports/lang/erlang/work/otp-OTP-21.3.8.18/erts/include/internal
-I/usr/ports/lang/erlang/work/otp-OTP-21.3.8.18/erts/emulator/sys/common
-I/usr/ports/lang/erlang/work/stage/usr/local/lib/erlang/erts-10.3.5.14/include/internal
I was surprised by the result:13 errors and 7 warnings, the shell output and errors and warnings description are in the links below.
My question is : why these errors occurs ? What is the wrong in what I did ?
Since this driver works perfectly in response to the ERTS networking tasks, then it's compiled by the ERTS without errors and the ERTS should use an OS C Language Compiler which is Clang by default and should add included headers files as I did, so why this did not work when I tried to do ?
https://ibb.co/bbtFHZ7
https://ibb.co/sF8QsDx
https://ibb.co/Lh9cDCH
https://ibb.co/W5Gcj7g
First things first:
In my knowledge the ERTS compile these drivers at boot time
No, ERTS doesn't compile the drivers. inet_drv.c is compiled as part of Erlang/OTP and linked into the beam.smp binary.
inet_drv is not a typical driver. Quoting the How to Implement a Driver section of the documentation:
A driver can be dynamically loaded, as a shared library (known as a DLL on Windows), or statically loaded, linked with the emulator when it is compiled and linked. Only dynamically loaded drivers are described here, statically linked drivers are beyond the scope of this section.
inet_drv is a statically loaded driver, and as such doesn't need to be loaded with erl_ddll.
On to the compilation errors. All the compiler parameters are automatically added for you when you run make, so if you need to call the compiler manually, better just check the command line that make generated and start from that. Let's look at the build log for the Debian Erlang package. Searching for inet_drv we get this command line (line breaks added):
x86_64-linux-gnu-gcc -Werror=undef -Werror=implicit -Werror=return-type -fno-common \
-g -O2 -fno-strict-aliasing -I/<<PKGBUILDDIR>>/erts/x86_64-pc-linux-gnu -D_GNU_SOURCE \
-DHAVE_CONFIG_H -Wall -Wstrict-prototypes -Wpointer-arith -Wmissing-prototypes \
-Wdeclaration-after-statement -DUSE_THREADS -D_THREAD_SAFE -D_REENTRANT -DPOSIX_THREADS \
-D_POSIX_THREAD_SAFE_FUNCTIONS -DBEAMASM=1 -DLIBSCTP=libsctp.so.1 \
-Ix86_64-pc-linux-gnu/opt/jit -Ibeam -Isys/unix -Isys/common -Ix86_64-pc-linux-gnu \
-Ipcre -I../include -I../include/x86_64-pc-linux-gnu -I../include/internal \
-I../include/internal/x86_64-pc-linux-gnu -Ibeam/jit -Ibeam/jit/x86 -Idrivers/common \
-Idrivers/unix -c \
drivers/common/inet_drv.c -o obj/x86_64-pc-linux-gnu/opt/jit/inet_drv.o
Some of it will be different since you're building on FreeBSD, but the principle stands - most of the time you'll want to just run make instead of invoking the compiler directly, but if you need to invoke the compiler, it will be much easier to start with the command line that make generated for you.

Problems with linking a library with a c program in linux

I want to run serial commands from a Bealgebone to a 4Dsystems display. Therefore I copied the c library found here into a directory and created a test program main.c:
#include "Picaso_const4D.h"
#include "Picaso_Serial_4DLibrary.h"
int main(int argc,char *argv[])
{
OpenComm("/dev/ttyUSB0", B115200); // Matches with the display "Comms" rate
gfx_BGcolour(0xFFFF);
gfx_Cls();
gfx_CircleFilled(120,160,80,BLUE);
while (1) {}
}
Now when I do gcc -o main main.c its says
main.c:2:37: fatal error: Picaso_Serial_4DLibrary.h: No such file or
directory
So I try linking it:
gcc main.c -L. -lPICASO_SERIAL_4DLIBRARY
which gives me the same error. Then I tried to create a static library:
gcc -Wall -g -c -o PICASO_SERIAL_4DLIBRARY PICASO_SERIAL_4DLIBRARY.C
which gives me this:
PICASO_SERIAL_4DLIBRARY.C:1:21: fatal error: windows.h: No such file
or directory compilation terminated.
What am I doing wrong? the git page clearly says this library is created for people who do not run windows.
Thanks in advance!
You're not getting a linker error; you're getting a preprocessor error. Specifically, your preprocessor can't find Picaso_Serial_4DLibrary.h. Make sure that it's in your include path; you can add directories to your include path using the -I argument to gcc.
You've had two problems. First was the picaso_whatever.h file that couldn't be found. You fixed that with the -I you added. But, now, the picaso.h wants windows.h
What are you building on? WinX or BSD/Linux?
If you're compiling on WinX, you need to install the "platform sdk" for visual studio.
If you're using mingw or cygwin, you need to do something else.
If on WinX, cd to the C: directory. Do find . -type f -name windows.h and add a -I for the containing directory.
If under Linux, repeat the find at the source tree top level. Otherwise, there is probably some compatibility cross-build library that you need to install.
Or, you'll have to find WinX that has it as Picaso clearly includes it. You could try commenting out one or more of the #include's for it and see if things are better or worse.
If you can't find a real one, create an empty windows.h and add -I to it and see how bad [or good] things are.
You may need the mingw cross-compiler. See https://forums.wxwidgets.org/viewtopic.php?t=7729
UPDATE:
Okay ... Wow ... You are on the right track and close, but this is, IMO, ugly WinX stuff.
The primary need of Picaso is getting a serial comm port connection, so the need from within windows.h is [thankfully] minimal. It needs basic boilerplate definitions for WORD, DWORD, etc.
mingw or cygwin will provide their own copies of windows.h. These are "clean room" reimplementations, so no copyright issues.
mingw is a collection of compile/build tools that let you use gcc/ld/make build utilities.
cygwin is more like: I'd like a complete shell-like environment similar to BSD/Linux. You get bash, ls, gcc, tar, and just about any GNU utility you want.
Caveat: I use cygwin, but have never used mingw. The mingw version of windows.h [and a suite of .h files that it includes underneath], being open source, can be reused by other projects (e.g. cygwin, wine).
Under Linux, wine (windows emulator) is a program/suite that attempts to allow you to run WinX binaries under Linux (e.g. wine mywinpgm).
I git cloned the Picaso library and after some fiddling, I was able to get it to compile after pointing it to wine's version of windows.h
Picaso's OpenComm is doing CreateFile [a win32 API call]. So, you'll probably need cygwin. You're opening /dev/ttyUSB0. /dev/* implies cygwin. But, /dev/ttyUSB0 is a Linux-like name. You may need some WinX-style name like "COM:" or whatever. Under the cygwin terminal [which gives you a bash prompt], do ls /dev and see what's available.
You can get cygwin from: http://cygwin.com/ If you have a 64 bit system, be sure to use the 64 bit version of the installer: setup-x86_64.exe It's semi-graphical and will want two directories, one for the "root" FS and one to store packages. On my system, I use C:\cygwin64 and C:\cygwin64_packages--YMMV.
Note that the installer won't install gcc by default. You can [graphically] select which packages to install. You may also need some "devel" packages. They have libraries and .h files that a non-developer wouldn't need. As, docs mention, you can rerun the installer as often as you need. You can add packages that you forgot to specify or even remove ones that you installed that you don't need anymore.
Remember that you'll need to adjust makefile -I and/or -L option appropriately. Also, when building the picaso library, gcc generated a ton of warnings about overflow of a "large integer". The code was doing:
#define control_code -279
unsigned char buf[2];
buf[0] = control_code >> 8;
buf[1] = control_code;
The code is okay, and the warning is correct [because the code is sloppy]. If the code had done:
#define control_code -279
unsigned char buf[2];
buf[0] = (unsigned) control_code >> 8;
buf[1] = (unsigned) control_code;
it probably would have been silent. Use -Wno-overflow in your Makefile to get rid of the warnings rather that edit 50 or so lines

Can the object files output by gcc vary between compilations of the same source with the same options?

Does the gcc output of the object file (C language) vary between compilations? There is no time-specific information, no change in compilation options or the source code. No change in linked libraries, environmental variables either. This is a VxWorks MIPS64 cross compiler, if that helps. I personally think it shouldn't change. But I observe that sometimes randomly, the instructions generated changes. I don't know what's the reason. Can anyone throw some light on this?
How is this built? For example, if I built the very same Linux kernel, it includes a counter that is incremented each build. GCC has options to use profiler information to guide code generation, if the profiling information changes, so will the code.
What did you analyze? The generated assembly, an objdump of object files or the executable? How did you compare the different versions? Are you sure you looked at executable code, not compiler/assembler/linker timestamps?
Did anything change in the environment? New libraries (and header files/declarations/macro definitions!)? New compiler, linker? New kernel (yes, some header files originate with the kernel source and are shipped with it)?
Any changes in environment variables (another user doing the compiling, different machine, different hookup to the net gives a different IP address that makes it's way into the build)?
I'd try tracing the build process in detail (run a build and capture the output in a file, and do so again; compare those).
Completely mystified...
I had a similar problem with g++. Pre 4.3 versions produced exactly the same object files each time. With 4.3 (and later?) some of the mangled symbol names are different for each run - even without -g or other recordings. Perhaps the use a time stamp or random number (I hope not). Obviously some of those symbols make it into the .o symbol table and you get a difference.
Stripping the object file(s) makes them equal again (wrt. binary comparison).
g++ -c file.C ; strip file.o; cmp file.o origfile.o
Why should it vary? It is the same result always. Try this:
for i in `seq 1000`; do gcc 1.c; md5sum a.out; done | sort | uniq | wc -l
The answer is always 1. Replace 1.c and a.out to suit your needs.
The above counts how many different executables are generated by gcc when compiling the same source for 1000 times.
I've found that in at least some environments, the same source may yield a different executable if the source tree for the subsequent build is located in a different directory. Example:
Checkout a pristine copy of your project to dir1. Do a full rebuild from scratch.
Then, with the same user on the same machine, checkout the same exact copy of your source code to dir2 (dir1 != dir2). Do another full rebuild from scratch.
These builds are minutes apart, with no change in the toolchain or any 3rd party libs or code. Binary comparison of source code is the same. However, the executable in dir1 has different md5sum than the executable in dir2.
If I compare the different executables in BeyondCompare's hex editor, the difference is not just some tiny section that could plausibly be a timestamp.
I do get the same executable if I build in dir1, then rebuild again in dir1. Same if I keep building the same source over and over from dir2.
My only guess is that some sort of absolute paths of the include hierarchy are embedded in the executable.
My gcc sometimes produces different code for exactly the same Input. The output object files differ in exactly one byte.
Sometimes this causes linker Errors, because one possible object file is invalid. Recompiling another version usually fixes the linker error.
The gcc Version is 4.3.4 on Suse Linux Enterprise.
The gcc Parameters are:
cc -std=c++0x -Wall -fno-builtin -march=native -g -I<path1> -I<path2> -I<path3> -o obj/file.o -c file.cpp
If someone experiences the same effect, then please let me know.

Resources