Frama-c syntax error on macro expansion - frama-c

I am getting the following syntax error:
../stat-time.h:58:[kernel] user error: Cannot find field st_atim
This is in the gnu stat-time.h by Paul Eggert. Here's the snippet causing the error:
#define STAT_TIMESPEC(st, st_xtim) ((st)->st_xtim)
long int get_stat_atime_ns(struct stat const *st) {
...
// 58:
return STAT_TIMESPEC(st, st_atim).tv_nsec;
...
}
I tried to preprocess the file first, then run frama-c on the preprocessed file, but that didn't help. Frama-c still reported the same error at the same location, even though the file was preprocessed correctly and the macro was correctly expanded! I invoked gcc as follows, for preprocessing:
gcc -E -C -I. -dD -nostdinc -D__FC_MACHDEP_X86_32 -I/usr/local/share/frama-c/libc
Any ideas?

I figured out the solution. Apparently, the frama-c headers in /usr/local/share/frama-c/libc/__fc_define_stat.h lacked the nsec granularity fields in struct stat. I added the following fields to struct stat to fix the problem:
unsigned long int st_atimensec;
unsigned long int st_mtimensec;
unsigned long int st_ctimensec;
Also, make sure to use the frama-c headers while configuring, e.g., configure CPP='gcc -E -C -dD -nostdinc -I/usr/local/share/frama-c/libc. If not, you will need to undefine the following two macros:
HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC, HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC, and define the following macro: HAVE_STRUCT_STAT_ST_ATIMENSEC in a header file, and include it in config.h or in __fc_define_stat.h

Related

What are the braces in this makefile rule for?

I am reading a makefile for a Qt-created project that has the following:
{backend}.cpp{release\}.obj::
$(CXX) -c $(CXXFLAGS) $(INCPATH) -Forelease\ #<<
$<
<<
(above code is using \t for recipe and is as written in makefile)
Both the rule and the recipe confuse me.
I'll start with {backend} in the rule. Obviously the same confusion for {release} as well. I assume this is a reference to a particular sub-directory named backend. I guess that ..\backend\release\bar.obj would be found as a legitimate target? But what part of make says this is legitimate syntax and what exactly happens here?
FWIW: This is in a section commented as: ##### implicit rules.
Version: GNU Make 4.2.1 Built for x86_64-unknown-cygwin
Bonus points:
Explain the use of #<< and << in the recipe... (Yes, I'm lacking in bash shell finesse...). Is this referencing the first prerequisite with $< and silently redirecting it? Why isn't it $$<?
Thanks.
That is an NMAKE batch-mode rule
https://learn.microsoft.com/en-us/cpp/build/batch-mode-rules?view=vs-2017
The equivalent GNU Make rule would be something like
backend/%.obj: release/%.cpp:
With the difference that, as the name suggests, these rules will invoke their recipes only once for all valid targets and expect the rule to create all of the targets in a single pass with the $< macro.
The << syntax is NMAKE's inline file feature
https://learn.microsoft.com/en-us/cpp/build/inline-files-in-a-makefile?view=vs-2017
This expands and captures everything between the angle brackets and saves it to a file, in this case a temporary file as no filename is specified after the brackets. The file is then passed to the compiler as a response file on the first line of the recipe through the # option.

Suppress warnings when building with GNU make in command line [duplicate]

This question already has an answer here:
Add compiler option without editing Makefile
(1 answer)
Closed 6 months ago.
Is there a way to suppress compiler warnings for GNU make and only show higher-order logs, i.e. errors?
Apparently, this should be possible using make -w as described here. However, for my version of GNU make (4.1), the man file specifies this as printing the current directory:
-w, --print-directory Print the current directory.
-W FILE
Consider FILE to be infinitely new.
If possible, this should be disabled both for make-internal warnings ($(warning ...)) and compiler-level warnings by gcc.
As pointed out in this post, it is not possible to directly add flags for the compiler. Furthermore, adding to existing CFLAGS variables (make CFLAGS+=-w) does not work either in most cases, as it ignores the append part and simply redefines the variable in the command line.
A very easy solution to fix this is by creating an empty dummy variable (once) inside your makefile and then defining it in case you need it:
# Add empty variable to add flags over command line
CDBG +=
CFLAGS += $(CDBG)
Which you then simply use as follows:
make CDBG=-w
as in https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
just add -w in your building command to suppress warnings, for example
gcc -Wall -w -o program pgmEcho.c pgm.c pgm.h

Shebang line C. How does it work?

I was reading the Advanced Programming in UNIX and stumbled upon this example. What is the shebang line doing here? Here's the top part of the code.
#!/usr/bin/awk -f
BEGIN {
printf("#include \"apue.h\"\n")
printf("#include <errno.h>\n")
printf("\n")
printf("static void pr_sysconf(char *, int);\n")
printf("static void pr_pathconf(char *, char *, int);\n")
printf("\n")
printf("int\n")
printf("main(int argc, char *argv[])\n")
printf("{\n")
printf("\tif (argc != 2)\n")
printf("\t\terr_quit(\"usage: a.out <dirname>\");\n\n")
FS="\t+"
while (getline <"sysopt.sym" > 0) {
printf("#ifdef %s\n", $1)
printf("\tprintf(\"%s is defined (val is %%ld)\\n\", (long)%s+0);\n", $1, $1)
printf("#else\n")
printf("\tprintf(\"%s is undefined\\n\");\n", $1)
printf("#endif\n")
printf("#ifdef %s\n", $2)
The shebang line is (on Linux and most Unixes) understood by execve(2). However, POSIX don't specify anything about it. Your script should be run by e.g. GNU awk, assuming that script is an executable file (and you probably want it to be accessible from your PATH variable).
So when something (probably your Unix shell, but could be something else) is executing with execve that script, the /usr/bin/awk program gets executed. You are betting that this awk program is some implementation of AWK
The OS's routines for executing a file look for the two characters #! at the start of a file, and if present, instead of directly loading the file as a binary executable, they call the executable file referenced by the rest of that line, along with any command line argument therein, then the original file as a final argument.
That's quite an involved description; a couple of examples make it clearer:
If myFile contains:
#!/bin/echo My path is
... and we make it executable:
$ chmod +x myFile
... then when we run it, we get:
$ ./myFile
My path is /home/slim/myFile
Or if we change its contents to:
#!/bin/cat
Hello
world
Then when we run it, it prints itself ...
$ ./myFile
#!/bin/cat
Hello
world
This is generally useful when command it invokes is an interpreter which can work with the contents, and itself ignores the shebang. Of course in many languages # denotes a comment, so we get this for free:
#!/bin/bash
#!/usr/bin/perl
#!/bin/awk -f
So essentially it arranges matters such that running myFile directly, is equivalent to running awk -f myFile.

Converting Qt project with a .pro file to project using CMake - Problems with moc

I have a project which compiles fine when I build it with a .pro file with QtCreator. I am trying to convert it to cmake, but have run into an issue.
EDITED WITH MINIMAL REPRODUCIBLE EXAMPLE:
Project folder structure:
src/foo.cpp --> #include "ui_foo.h"
src/bar.cpp --> #include "bar.moc"
inc/foo.h
ui/foo.ui
Expected compilation flow (observed flow when using qmake):
(1) moc inc/foo.h -o moc_foo.cpp
(2) moc src/bar.cpp -o bar.moc
(3) uic ui/foo.ui -o ui_foo.h
(4) gcc src/foo.cpp -o foo.o
(5) gcc src/bar.cpp -o bar.o
(6) gcc moc_foo.cpp -o moc_foo.o
(7) ld foo.o bar.o moc_foo.o -o foobar
CMakeLists.txt(1):
set(CMAKE_INCLUDE_CURRENT_DIR ON )
set(CMAKE_AUTOMOC ON )
set(CMAKE_AUTOUIC ON )
add_executable(foobar src/foo.cpp src/bar.cpp)
moc_foo.cpp is not created (step 1 & 6 are missed) and doesn't get added to add_executable in step 7. Undefined references to vtable occur because of missing object. I think this is because foo.cpp and foo.h are in different folders.
CMakeLists.txt(2):
set(CMAKE_INCLUDE_CURRENT_DIR ON )
qt5_wrap_cpp(foobar_moc inc/foo.h src/bar.cpp)
qt5_wrap_ui (foobar_ui ui/foo.ui)
add_executable(foobar src/foo.cpp src/bar.cpp ${foobar_moc} ${foobar_ui})
moc_bar.cpp is generated instead of bar.moc in step 2. I get a compiler error because bar.moc cannot be found in step 5.
You're making your own life unnecessary hard by trying to moc a .cpp file.
Despite the name qt5_wrap_cpp actually takes header files as its argument and invokes the moc to generate matching cpp files:
qt5_wrap_cpp(foobar_moc inc/foo.h)
# ${foobar_moc} will contain the name
# of the .cpp file created for foo.h
# which we pass to add_executable()
Note that typically you will have a foo.cpp source file lying around somewhere as well, which together with the .cpp generated by the moc provides the full implementation for the class defined in foo.h.
Now, if you really want to invoke the moc on a .cpp file, the procedure is slightly different. Here, since the class definition is no longer in a header file, the source file generated by the moc cannot access the class definition it refers to. As a result, the generated source file can no longer be compiled on its own. Instead, you need to pull it into the original source file after the class definition using #include, which is not very nice.
What's worse is that for CMake to invoke the moc command, the generated source file still needs to be part of the dependency chain somewhere, which makes everything quite ugly.
We will use the qt5_generate_moc command to invoke the moc on bar.cpp (as qt5_wrap_cpp would also add the generated source to the build, which would break):
qt5_generate_moc(src/bar.cpp ${CMAKE_BINARY_DIR}/bar.moc)
Note that we place the generated file in the binary tree to not pollute the source tree with generated files. If you have set an AUTOGEN_BUILD_DIR, you might want to put the generated file there instead. In order to allow the #include to find the generated file, we add the binary tree to the include directories for our project:
target_include_directories(foobar PUBLIC ${CMAKE_BINARY_DIR})
And finally, we need a custom target for the build step dependency. Without this, the moc command would never actually get invoked:
add_custom_target(moc_dummy DEPENDS ${CMAKE_BINARY_DIR}/bar.moc)
add_dependencies(foobar moc_dummy)
Bottom line: Just move all your class definitions to header files and then moc those. There's no disadvantage and you will save yourself lots of ugly boilerplate.
The easiest thing to do would be to add AUTOMOC property, and let CMake handle QT mocs automatically
set_target_properties(MyProj PROPERTIES AUTOMOC TRUE)

Qprocess and command MSDOS

I want execute a commande line with QProcess :
QString elf_path=C:\\files\\file.elf;
QString appli = "readelf.exe -a "+elf_path+" >>C:\\work\\essai.txt";
QProcess *process = new QProcess();
process->execute(appli);
but QT display this error :
readelf: Error: '>>C:\work\essai.txt': No such file
Can you help me ?
The QProcess::execute command will take the first parameter as the executable and pass each of the next parameters as arguments to that executable. So the error is because the readelf executable is receiving ">>C:\work\essai.txt" as an argument.
There is more than one solution to fix this.
Rather than redirecting the output to the text file, you could read the output from the readelf command (readAllStandardOutput), open a file essai.txt from Qt and append the output yourself. You should probably call waitForFinished() before retrieving the output.
Alternatively, there's a function in QProcess called setStandardOutputFile which takes a filename to redirect the output from the process to that file, which may be easier: -
QProcess* proc = new QProcess;
QString appli = "readelf.exe -a " + elf_path;
proc->setStandardOutputFile("C:\\work\\essai.txt", QIODevice::Append);
proc->start(appli);
Finally, you could create a shell script and call that with your parameters where the shell script would know that the final input parameter is to use for the output redirection.
QProcess::execute is static method. You should not create instance of QProcess in your case. Try next code
const QString path2exe = "readelf.exe";
QStringList commandline;
commandline << "-a";
commandline << elfPath;
commandline << "c:\\work\\essai.txt"
QProcess::execute( path2exe, commandline );
It looks like readelf is seeing your redirection as another file, which is valid since readelf can handle more than one on the command line.
Hence, the Qt process stuff is not handling redirection as you expect.
Within a shell of some sort, the redirections are used to set up standard input/output (and possibly others) then they're removed from the command line seen by the executable program. In other words, the executable normally doesn't see the redirection, it just outputs to standard output which the shell has connected to a file of some sort.
In order to fix this, you'll either have to run a cmd process which does understand redirection (passing the readelf command as a parameter) or use something like the method QProcess::readAllStandardOutput() to get the output into a byte array instead of writing to a temporary file.

Resources