"gcc -DSOMENAME"; "SOMENAME" not getting defined - c

I am trying to execute a PintOS command pintos -f (do not worry if you are not familiar with PintOS). Internally, init.c program is called, whose parse_options() function handles the command line arguments passed. Below is the relevant snippet of init.c
static char **
parse_options (char **argv)
{
for (; *argv != NULL && **argv == '-'; argv++)
{
char *save_ptr;
char *name = strtok_r (*argv, "=", &save_ptr); //fn to tokenise the string
char *value = strtok_r (NULL, "", &save_ptr);
if (!strcmp (name, "-h"))
usage ();
else if (!strcmp (name, "-q"))
power_off_when_done = true;
else if (!strcmp (name, "-r"))
reboot_when_done = true;
/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
#ifdef FILESYS
else if (!strcmp (name, "-f"))
format_filesys = true;
#endif
/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
else if (!strcmp (name, "-rs"))
random_init (atoi (value));
else if (!strcmp (name, "-mlfqs"))
thread_mlfqs = true;
#ifdef USERPROG
else if (!strcmp (name, "-ul"))
user_page_limit = atoi (value);
#endif
else
PANIC ("unknown option `%s' (use -h for help)", name);
}
return argv;
}
As per the code inside the $$$$ section, the -f option passed will be processed only if FILESYS is defined.
On executing make, the following command is executed
gcc -m32 -c ../../threads/init.c -o threads/init.o -g -msoft-float -O -fno-stack- protector -nostdinc -I../.. -I../../lib -I../../lib/kernel -Wall -W -Wstrict-prototypes -Wmissing-prototypes -Wsystem-headers -DUSERPROG -DFILESYS -MMD -MF threads/init.d
Here, -DUSERPROG and -DFILESYS options are provided to define FILESYS and USERPROG, so that the relevant sections of the code can be executed. However, somehow, FILESYS is not getting defined, as evident from the following output of pintos -f command
Kernel command line: -f
Kernel PANIC at ../../threads/init.c:261 in parse_options(): unknown option `-f' (use -h for help)
Several other tests confirm that FILESYS not getting defined IS the issue. I checked the gcc syntax and even wrote the following Dummy program to check the -DNAME option with gcc.
DummyProg.c
#include "stdio.h"
int main()
{
#ifdef CHECK
printf("WORKING\n");
#endif
return 0;
}
With gcc -DCHECK DummyProg.c and ./a.out, WORKING was displayed on the screen, conforming the validity of syntax etc. The gcc version I am using is gcc (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3
Could someone please point how to resolve this issue.

The compiler can help you understand this; the trick is to capture the proprocessed code with the #define statements left in:
gcc -E -dD ...blah...
You have to remove the -c and -o <outfile> options from the compile command, but otherwise leave it unchanged, apart from adding the two new options.
-E tells it to do the preprocess step only, and output it to screen.
-dD tells it to leave in the #define and #undef directives.
My guess is that your code has a #undef FILESYS directive somewhere, and it's overriding your -DFILESYS option.

To debug issues like this, run gcc with -E. This will just run the code through the preprocessor cpp. Look into the output file to see what the input of the C compiler would be after the post-processing step.

are you sure you are building the entire executable/library/...?
looking at the command that gets triggered when calling make, only a single file is compiled into an intermediate object file. no linking into the final binary happens.
so it guess that you are still using an outdated build. try going to the toplevel source directory and execute:
make clean && make

Related

How to send a variable from batch file to a C program?

How to use a variable from a batch file and send the value to a variable in a C file/program?
I absolutely do not know how to do this, and I don't know if it is even possible.
I am thinking about something like this:
Batch file:
#echo off
set name= %1
::somehow set a variable in myfile.c to "name"'s value
gcc myfile.c -o readf
.\readf
C file:
#include <stdio.h>
int main() {
char(or any other) name[] = /* the value of "name" in the batch file */
printf(name);
return 0;
}
As pointed out by #kopecs, it seem that you want to define a macro in the command line while compiling your code. This would be useful if you want to define some constant that will be included in the binary for future execution, but not if you simply want to get argument from the command line.
Modify your code the following way to use the preprocessor
#include <stdio.h>
#ifndef VARIABLE
// In case you want to define a default value for your VARIABLE
#define VARIABLE "default value"
#endif
int main() {
char(or any other) name[] = VARIABLE // VARIABLE is a preprocessing macro that will be defined by the compiler
printf(name);
return 0;
}
Then invoke the compiler with the following preprocessor option
#echo off
set name=%1
::somehow set a variable in myfile.c to "name"'s value
gcc myfile.c -o readf -D "VARIABLE=%name%" -Wall -Wextra -pedantic
.\readf
Documentation quote for the argument
-D name=definition
The contents of definition are tokenized and processed as if they appeared during translation phase three in a ‘#define’ directive. In particular, the definition is truncated by embedded newline characters.
If you are invoking the preprocessor from a shell or shell-like program you may need to use the shell’s quoting syntax to protect characters such as spaces that have a meaning in the shell syntax.
If you wish to define a function-like macro on the command line, write its argument list with surrounding parentheses before the equals sign (if any). Parentheses are meaningful to most shells, so you should quote the option. With sh and csh, -D'name(args…)=definition' works.
-D and -U options are processed in the order they are given on the command line. All -imacros file and -include file options are processed after all -D and -U options.
However, I would recommend using command line argument for your program, that would be more flexible and avoid to recompile it each time you want to change it (unless you want to redistribute the binary with the hardcoded string).
#include <stdio.h>
int main(int argc, char* argv[]) {
// add some sanity checking against argc before getting the value in argv
char(or any other) name[] = argv[1];
printf(name);
return 0;
}
and after compiling your code the with
gcc myfile.c -o readf -Wall -Wextra -pedantic
Just invoke with
.\readf name_value

How should I handle a value that is never used?

I don't always use all return values, and sometimes I must handle return values. For instance:
$ make
gcc -pedantic -std=c99 -Wall -O3 -ledit -g -DVERSION=\"v0.160425-2-gc443\" -c -o main.o main.c
main.c: In function ‘int_handler’:
main.c:532:5: warning: ignoring return value of ‘write’, declared with attribute warn_unused_result [-Wunused-result]
write(fileno(stdin), s, sizeof s - 1);
^
gcc -o shell main.o errors.c util.c pipeline.c -ledit
What should I do to avoid the warning? Is there a good way to "use" a variable like writing it to /dev/null so that the compiler won't complain? My own idea is this, which deals with the problem without ignoring the error and I can commit my code without warnings and deal with this later:
void int_handler(int signum) {
if (write(fileno(stdin), s, sizeof s - 1)) {
} else {}
}
Typically to suppress this warning, you can do:
(void)write(fileno(stdin), s, sizeof s - 1);
But the reason for the warning is because write() is declared with an attribute in the header (<unistd.h>) which leads to the warning.
This (attribute) is not done for every function but selectively. For example, printf()'s return is typically ignored.
Since, you would want to check the results of IO operation, it's done for write().
So, if you really want to ignore the result, you can use the (void)func(...); to suppress this.
First of all, in case of file handling functions in production-quality code, you should almost certainly handle all return values.
Otherwise, the standard way to ignore a variable or a function result, is to cast it to (void).
It is a bad idea to not take in account the return value of a call to write, as an I/O may fail it is important to take care of such an event. If you really want to remove the warning, you should explicitly ignore the return value:
(void)write(...);
The prototype for write in the header file unistd.h has been declared as follows
extern ssize_t write (int __fd, const void *__buf, size_t __n) __wur
and __wur has been defined as (in cdefs.h)
# if __USE_FORTIFY_LEVEL > 0
# define __wur __attribute_warn_unused_result__
# endif
#else
# define __attribute_warn_unused_result__ /* empty */
So when you are compiling with fortify switch on, wur gets defined as
__attribute_warn_unused_result. This attribute essentially tells the compiler to throw out warning if return value of function is not used.
You can redirect your stdout and stderr to /dev/null
gcc -c file.c > /dev/null 2>&1
and get rid of the warning (though even error is redirected to null) or you can redirect to file as
gcc -c warn.c > xx 2>&1
Hope this helps . And like said above, always check the value of "write", the error will automatically vanish
:)

Return address GDB: .exe differs from .elf?

I'm using GDB to return an address of a local static variable in my c code (pressureResult2 in this case), this is working fine for the ARM output: The .elf file.
However, if I use a build configuration for windows, creating a .exe, the variable I'm asking for can't be found.
What I'm using for returning the address of the variable:
sensorOffset::pressureResult2
Code:
static void sensorOffset (uint8_t axle)
{
static int16_t pressureResult2 = 400;
int16_t pressureResult = 0;
if (axle == AXLE_FRONT)
{
/* Always copy the actual value first to the value with offset */
CtisMach.front.tPressureSensorOffset = CtisMach.front.tPressureAct;
.... and so on
Is someone known with this issue? Is the command different for a windows executable? Or am I just doing something wrong?
To get the most obvious ones out:
Can you read an global static?
Yes, no problem
Does GDB notice anything about debug symbol?
No, the usual "Reading symbol from file.exe .. done" appears.
Does it work with .elf?
Yes, it does.
To answer the comments:
The code is compiled with the following:
cflags := \
-O0 \
-g3 \
-Wall \
-c \
-MD \
-fmessage-length=0 \
-fpermissive \
-I/mingw/include \
-I/usr/include \
-I/local/include \
-D WINDOWS \
$(CONFIGFLAGS) \
$(INCLUDES)
lnkflags := \
-Wl,--enable-stdcall-fixup \
-static-libgcc \
-static-libstdc++ \
$(CONFIGFLAGS) \
$(EXT_LIBDIR)
od_flags := \
--dwarf
Since I already mentioned it doesn't complain about debug variables symbols and I can read the global statics as well this doesn't appear to be the issue, or am I wrong? It should complain about not having debug symbols without -g right? Edit: Andreas reproduced this situation, but I still can't seem to fix it.
To do anything useful with the variable:
static int16_t pressureResult2 = 0;
if (pressureResult2 < 100)
{
pressureResult2++;
}
else
{
pressureResult2 = 0;
}
NOTE: This is just an example, same problem counts for all local statics in the code (that is too large to dump on SO).
GDB response on "Info variables", my variable "pressureResult2" is placed in the category Non-debugging symbols, might this be the issue?:
To see if the -g flag is actually doing something, without -g:
p& randomvar
$1 = (<data variable, no debug info> *) 0x4eade2 <randomvar>
with -g
p& randomvar
$1 = (uint16_t *) 0x4eade2 <randomvar>
So it's active for sure, but its still not possible to return local statics.
The only remarkable things so far is how the variable I'm looking for is categorized into Non-debugging symbols.
Compiling the code snipped of Andreas works including returning the address of the variable, my own code however, not much.
Most likely, you need to add the -g flag to the compiler invocation to add debugging information, and remove optimization flags like -O2. Given the following .c source file, using a cygwin environment on MS Windows:
#include <stdio.h>
static int globalstatic = 512;
static void sensorOffset (uint8_t axle) {
static int16_t pressureResult2 = 400;
pressureResult2++;
printf("%d %d\n", globalstatic, pressureResult2);
}
int main() {
int i = 0;
for (i = 0; i < 10; i++) {
sensorOffset(42);
}
return 0;
}
When compiled to an .exe file with -O2, your observation is reproduceable - gdb recognizes the global static variable, but not the local one (even though -g was specified):
C:> gcc -g -O2 -Wall -pedantic -o static static.c
C:> gdb static.exe
(gdb) break main
(gdb) run
Breakpoint 1, main () at static.c:14
14 int main() { Breakpoint 1, 0x0000000100401128 in main ()
(gdb) print globalstatic
$1 = 512
(gdb) print sensorOffset::pressureResult2
No symbol "sensorOffset" in current context.
When removing the -O2 flag, gdb does recognize the local static variable:
C:> gcc -g -Wall -pedantic -o static static.c
C:> gdb static.exe
(gdb) break main
(gdb) run
Breakpoint 1, main () at static.c:12
12 int i = 0;
(gdb) print sensorOffset::pressureResult2
$1 = 400

Calling execve bash on bash scripts can't find arguments

I have two (Ubuntu Linux) bash scripts which take input arguments. They need to be run simultaneously. I tried execve with arguments e.g.
char *argv[10] = { "/mnt/hgfs/F/working/script.sh", "file1", "file2", NULL };
execve(argv[0], argv, NULL)
but the bash script can't seem to find any arguments at e.g. $0, $1, $2.
printf "gcc -c ./%s.c -o ./%s.o\n" $1 $1;
gcc -c ./$1.c -o ./$1.o -g
exit 0;
output is gcc -c ./main.c -o ./main.o
and then a lot of errors like /usr/include/libio.h:53:21: error: stdarg.h: No such file or directory
What's missing?
Does your script start with the hashbang line? I think that's a must, something like:
#!/bin/bash
For example, see the following C program:
#include <stdio.h>
#include <unistd.h>
char *argv[10] = { "./qq.sh", "file1", NULL };
int main (void) {
int rc = execve (argv[0], argv, NULL);
printf ("rc = %d\n", rc);
return 0;
}
When this is compiled and run with the following qq.sh file, it outputs rc = -1:
echo $1
when you change the file to:
#!/bin/bash
echo $1
it outputs:
file1
as expected.
The other thing you need to watch out for is with using these VMWare shared folders, evidenced by /mnt/hgfs. If the file was created with a Windows-type editor, it may have the "DOS" line endings of carriage-return/line-feed - that may well be causing problems with the execution of the scripts.
You can check for this by running:
od -xcb /mnt/hgfs/F/working/script.sh
and seeing if any \r characters appear.
For example, if I use the shell script with the hashbang line in it (but appen a carriage return to the line), I also get the rc = -1 output, meaning it couldn't find the shell.
And, now, based on your edits, your script has no trouble interpreting the arguments at all. The fact that it outputs:
gcc -c ./main.c -o ./main.o
is proof positive of this since it's seeing $1 as main.
The problem you actually have is that the compiler is working but it cannot find strdarg.h included from your libio.h file - this has nothing to do with whether bash can see those arguments.
My suggestion is to try and compile it manually with that command and see if you get the same errors. If so, it's a problem with what you're trying to compile rather than a bash or exec issue.
If it does compile okay, it may be because of the destruction of the environment variables in your execve call.

undefined reference to function declared in *.h file

I am a unskilled programmer and new to linux, I run into a problem when complining. I have two files 'ex_addinst.c' and 'lindo.h' in the same folder, I input command :
g++ -c ex_addinst.c
then, a object file ex_addinst.o is genetated with a warning:
ex_addinst.c: In function ‘int main()’:
ex_addinst.c:80: warning: deprecated conversion from string constant to ‘char*’
then I leak them with
g++ -Wall -o ex_addinst ex_addinst.o
and get the following info:
ex_addinst.o: In function `main':
ex_addinst.c:(.text+0x2b): undefined reference to `LSloadLicenseString'
ex_addinst.c:(.text+0x75): undefined reference to `LSgetVersionInfo'
ex_addinst.c:(.text+0xae): undefined reference to `LScreateEnv'
ex_addinst.c:(.text+0x10a): undefined reference to `LSgetErrorMessage'
...
...
ex_addinst.c:(.text+0x1163): undefined reference to `LSdeleteEnv'
collect2: ld returned 1 exit status
I guess that the header file 'lindo.h' is not complied into the .o file, but I have no idea what to do now. I have tried gcc, but get the same error. the version of my g++ and gcc is 4.4.5. I am using Ubuntu 10.10.
All the functions and structures have been declared in 'lindo.h'.
part of ex_addinst.c is as follows:
#include <stdio.h>
#include <stdlib.h>
/* LINDO API header file */
#include "lindo.h"
enter code here
int CALLTYPE LSwriteMPIFile(pLSmodel pModel,
char *pszFname);
/* Define a macro to declare variables for
error checking */
#define APIERRORSETUP \
int nErrorCode; \
char cErrorMessage[LS_MAX_ERROR_MESSAGE_LENGTH] \
/* Define a macro to do our error checking */
#define APIERRORCHECK \
if (nErrorCode) \
{ \
if ( pEnv) \
{ \
LSgetErrorMessage( pEnv, nErrorCode, \
cErrorMessage); \
printf("nErrorCode=%d: %s\n", nErrorCode, \
cErrorMessage); \
} else {\
printf( "Fatal Error\n"); \
} \
exit(1); \
} \
#define APIVERSION \
{\
char szVersion[255], szBuild[255];\
LSgetVersionInfo(szVersion,szBuild);\
printf("\nLINDO API Version %s built on %s\n",szVersion,szBuild);\
}\
/* main entry point */
int main()
{
APIERRORSETUP;
pLSenv pEnv;
pLSmodel pModel;
char MY_LICENSE_KEY[1024];
/*****************************************************************
* Step 1: Create a model in the environment.
*****************************************************************/
nErrorCode = LSloadLicenseString("home/li/work/tools/lindo/lindoapi/license/lndapi60.lic", MY_LICENSE_KEY);
if ( nErrorCode != LSERR_NO_ERROR)
{
printf( "Failed to load license key (error %d)\n",nErrorCode);
exit( 1);
}
......
......
......
APIERRORCHECK;
{
int nStatus;
double objval=0.0, primal[100];
/* Get the optimization result */
nErrorCode = LSgetInfo(pModel, LS_DINFO_GOP_OBJ, &objval);
APIERRORCHECK;
LSgetMIPPrimalSolution( pModel, primal) ;
APIERRORCHECK;
printf("\n\nObjective = %f \n",objval);
printf("x[0] = %f \n",primal[0]);
printf("x[1] = %f \n",primal[1]);
/* Get the linearity of the solved model */
nErrorCode = LSgetInfo (pModel, LS_IINFO_GOP_STATUS, &nStatus);
APIERRORCHECK;
/* Report the status of solution */
if (nStatus==LS_STATUS_OPTIMAL || nStatus==LS_STATUS_BASIC_OPTIMAL)
printf("\nSolution Status: Globally Optimal\n");
else if (nStatus==LS_STATUS_LOCAL_OPTIMAL)
printf("\nSolution Status: Locally Optimal\n\n");
else if (nStatus==LS_STATUS_INFEASIBLE)
printf("\nSolution Status: Infeasible\n\n");
}
/* >>> Step 7 <<< Delete the LINDO environment */
LSdeleteEnv(&pEnv);
/* Wait until user presses the Enter key */
printf("Press <Enter> ...");
getchar();
}
part of 'lindo.h' is:
/*********************************************************************
* Structure Creation and Deletion Routines (4) *
*********************************************************************/
pLSenv CALLTYPE LScreateEnv(int *pnErrorcode,
char *pszPassword);
pLSmodel CALLTYPE LScreateModel(pLSenv pEnv,
int *pnErrorcode);
int CALLTYPE LSdeleteEnv(pLSenv *pEnv);
int CALLTYPE LSdeleteModel(pLSmodel *pModel);
int CALLTYPE LSloadLicenseString(char *pszFname, char *pachLicense);
void CALLTYPE LSgetVersionInfo(char *pachVernum, char *pachBuildDate);
Thank you!
Thank you guys answering my problem. As you suggested, I need to link the library when complining. I have gotten the executable file with:
gcc -o ex_addinst ./ex_addinst.o -L/home/li/work/tools/lindo/lindoapi/bin/linux64 -m64 -llindo64 -lmosek64 -lconsub3 -lc -ldl -lm -lguide -lpthread -lsvml -limf -lirc
but there comes another problem when run the executable file ex_addinst: after run:
./ex_addinst
there comes:
./ex_addinst: error while loading shared libraries: liblindo64.so.6.0: cannot open shared object file: No such file or directory
The tricky thing is, liblindo64.so.6.0 is in the lib folder which contains:
libconsub3.so libirc.so liblindojni.so libmosek64.so.5.0 lindo.par
libguide.so liblindo64.so liblindojni.so.6.0.3 libsvml.so placeholder
libimf.so liblindo64.so.6.0 libmosek64.so lindoapivars.sh runlindo
I have created symbolic links between liblindo64.so.6.0 and liblindo64.so with
ln -sf liblindo64.so.6.0 liblindo64.so
but it doesn't help.
Can anyone tell me what is wrong here?
(I am not sure I should put this question in a new post, but I think currently it is better to follow the old one)
Ok, lindo.h contains the prototypes for those functions, but where are the functions actually defined? If they're in another C file you need to compile that one too, and link both the object files together.
If the functions are part of another static library, you need to tell the linker to link that library along with your object file.
If they're defined with a shared library, you can probably get g++ to still link to it at compile time, and take care of the library loading etc. Otherwise you'll need to load the library at runtime and reference the functions from the library. This Wikipedia article on dynamic loading of shared libraries contains some example code.
Try
g++ -Wall -o ex_addinst ex_addinst.c
instead of
g++ -Wall -o ex_addinst ex_addinst.o
You want to compile the .c file, not the .o file.
You need to tell gcc to link with the library or object file(s) that contain the LS... functions you're using. The header file tells the compiler how to call them, but the linker needs to know where to get the compiled code from.
undefined reference to ... is not a declaration problem. The compiler fails because it can't find symbols (objects) which are related to those declared functions.
In your case, you use the Limbo API, and include the header file, but you don't tell the compiler to link with the library : that's why it doesn't find symbols.
EDIT : I had forgotten the part when you say you're new to Linux. To link with the library, you need to use the -L/-l options of g++. man g++ is always a good read, and the Limbo's documentation should be, too.

Resources