Get built arguments in C - c

Is there any way to check the arguments used to compile?
Like:
gcc -std=c99 -ggdb3 source.c -o sate-enak
In source.c:
...
#ifdef (-ggdb3 variable is defined)
do_some_function();
#else
do_another_function();
#endif
...
With using this method, I can find out if the program is compiled for production or product.

With gcc, not to my knowledge but you can achieve the same goal with a macro:
In your Makefile:
CFLAGS_DEBUG = -ggdb3 -DDEBUG
CFLAGS = -std=c99 $(CFLAGS_DEBUG)
then in your program:
#ifdef DEBUG
do_some_function();
#else
do_another_function();
#endif

There isn't an easy way to spot the options used by the compiler. All else apart, most programs are built from many source files, and those source files may have been compiled with different sets of options.
Usually, if you want to know, you control it with a command-line #define:
gcc -DMODE=MODE_OPTIM -O3 …
gcc -DMODE=MODE_DEBUG -ggdb3 …
where you have a header that defines the meaning of MODE_OPTIM and MODE_DEBUG:
enum CompilationMode { MODE_OPTIM, MODE_DEBUG };
#ifndef MODE
#define MODE MODE_DEBUG
#endif
extern enum CompilationMode compiled_for;
And somewhere you define that:
enum CompilationMode compiled_for = MODE;
And then you can test compiled_for wherever you need to know which mode the program was built with.
Actually, this is runtime decision making. For compile time decision making, you replace the enum with:
#define MODE_OPTIM 0
#define MODE_DEBUG 1
and you can test:
#if MODE == MODE_DEBUG
do_some_function();
#else
do_another_function();
#endif

Related

Generate #include macro from environment variable

as you say, it works.
But can I build -in some way- the string for the include directive ?
Something like
in .login
setenv REPO "/tmp"
compile
# gcc -D"REPO=${REPO}" source.c
in source.c
#ifdef REPO
#include ${REPO}/my_dir/my_file.h
#endif
thanks
As Joachim writes, in GCC you can use the -D flag to #define things from the command-line:
gcc -DTEST source.c
// in source.c
#include <stdio.h>
int main() {
#ifdef TEST
printf("TEST macro is #defined!\n"); // only runs if -DTEST
#endif
return 0;
}
You can easily plug in environment variables (at compile-time) via this
mechanism:
gcc "-DTEST=$MY_ENV_VAR" source.c
If you need to use the run-time value of the environment variable, then the macro preprocessor (#define, #ifdef, ...) can't help you. Use getenv() instead, and forget about macros.
More to the point:
#include TEST
int main() {
printf("Hello world!\n");
return 0;
}
Will work fine only if compiled with "-DTEST=<stdio.h>" (note the quotes).

be64toh not linking or being declared when compiling with -std=c99

When I compile the following program (the code for all the defines I've gotten from 64 bit ntohl() in C++? which seemed sensible):
#include <stdint.h>
#if defined(__linux__)
#include <endian.h> //htobe64,be64toh
#include <arpa/inet.h> //ntohs, ntohl, htonl, htons
#elif defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/endian.h>
#elif defined(__OpenBSD__)
#include <sys/types.h>
#define be16toh(x) betoh16(x)
#define be32toh(x) betoh32(x)
#define be64toh(x) betoh64(x)
#endif
int main()
{
int64_t i = 0x1212121234343434;
int64_t j = be64toh(i);
return 0;
}
I get a linking error when compiling it with the following command (I'm running linux):
gcc -std=c99 endian_test.c -o endian
The error i receive is:
user#host ~/src/c $ gcc -std=c99 derp.c
endian_test.c: In function ‘main’:
endian_test.c:17:2: warning: implicit declaration of function ‘be64toh’ [-Wimplicit-function-declaration]
int64_t j = be64toh(i);
^
/tmp/ccYonfH4.o: In function `main':
endian_test.c:(.text+0x23): undefined reference to `be64toh'
collect2: error: ld returned 1 exit status
Which to me indicates two things, the header itself is included but doesn't really contain the functions/macros needed for this to work and because that means the compiler hopes it's gonna find the function later it tries to go ahead anyway but fails when trying to link.
But if i use the following command to compile (just remove -std=c99):
gcc endian_test.c -o endian
Everything is smooth as butter and works. Any idea why it's happening and what i could do to remedy it? To me it doesn't make sense that functions given by the kernel (or am i mistaken in that fact?) change depending on what standard i use when compiling?
Thanks in advance!
Without explicit -std= option, calling gcc is the same as -std=gnu89 with means C89 + GNU extensions. The GNU extensions will enable macros which will enable the presence of the functions in your header.
If you see the be64toh manual, you will see that it needs the _BSD_SOURCE to be defined. So on Linux #define it before you include <endian.h>.
I had this problem. The solution was to declare not only
#define _BSD_SOURCE
but also
#define __USE_BSD
https://github.com/tailhook/zerogw/pull/34/files#r32008569
Recent changes to glibc has meant you need
#define _DEFAULT_SOURCE
instead of
#define _BSD_SOURCE
Deprecation of _BSD_SOURCE and _SVID_SOURCE feature macros

File Global Define

I am making a small, library, and I want to give the user the option to disable the parts they do not require.
lib.h
#ifndef ONLY_BASICS
void complexFunction(void);
#endif
lib.c
#ifndef ONLY_BASICS
void complexFunction(void) {
printf("damn, this is complex alright!\n");
}
#endif
main.c
#define ONLY_BASICS
#include "lib.h"
I have seen this being done in other libraries, what am I missing?
You can make users control the build using the prepossessing macros from the compiler without editing the code. If you use GCC use the switch -D followed by the macro name. On Microsoft compiler use the /D option.
For example using GCC, I have:
#include <stdio.h>
int main(int argc, char **argv) {
#ifdef SAYHI
#ifdef CAPITAL
printf("HI\n");
#else
printf("hi\n");
#endif
#elif SAYHELLO
#ifdef CAPITAL
printf("HELLO\n");
#else
printf("hello\n");
#endif
#else
#ifdef CAPITAL
printf("SAY SOMETHING\n");
#else
printf("say something\n");
#endif
#endif
return 0;
}
The user can enable and disable what he want via -DMACRO without editing the code, example:
$ gcc main.c
$ a.exe
say something
$
$ gcc main.c -DCAPITAL
$ a.exe
SAY SOMETHING
$
$ gcc main.c -DSAYHI -DCAPITAL
$ a.exe
HI
$
$ gcc main.c -DSAYHELLO
$ a.exe
hello
$
It seems you're misunderstanding what a library is and what it's used for. Most (all?) linkers already do what you're trying by not including unreferenced symbols from libraries - it's why with gcc, for instance, you need to put the libraries at the end of the command line after the list of source files that contain references to library functions.
What you're doing seems to be confusing this behaviour with compile-time options for the library itself. In that case, you can use the #ifndef blocks as you have in lib.h and lib.c, but you shouldn't need to do anything in main.c - the library will already have been built without complexFunction. You may want to have your library build process generate a header that describes which functionality is available.

Including a typedef in two header files

I have this in ball.h:
#ifndef BALL_H_
#define BALL_H_
...
typedef void *PBALL ;
...
#endif
in paddle.h I have:
#ifndef PADDLE_H_
#define PADDLE_H_
...
int contact_made(struct pppaddle*, PBALL);
...
#endif
I get an error in paddle.h because it doesn't know about PBALL. So if I add:
#ifndef BALL_H_
#include "ball.h"
#endif
to paddle.h (with or without the if statement) it works in my Cygwin environment. But in Linux when I go to compile I get: "multiple definition of `newPBALL'" error on the source file that uses PBALL and also on the functions defined in ball.h. How can I get paddle.h to understand PBALL without running into these problems in Linux?
My ball.c file:
struct newball {
int x_pos, x_dir, y_pos, y_dir, y_delay, y_count, x_delay, x_count;
char symbol;
};
typedef struct newball *ball_struct_ptr;
struct newball the_ball;
#include "ball.h"
PBALL newPBALL() {
the_ball.y_pos = Y_INIT;
the_ball.x_pos = X_INIT;
the_ball.y_count = the_ball.y_delay = Y_DELAY;
the_ball.x_count = the_ball.x_delay = X_DELAY;
the_ball.y_dir = 1;
the_ball.x_dir = 1;
the_ball.symbol = DFL_SYMBOL; //Set the symbol of the ball
PBALL ptr = &the_ball;
return ptr;
}
Well instead of trying to import one header file into another (which worked in Cygwin but not Linux) or not importing the header into the other header (which worked for Linux but not Cygwin) I did this in both header files:
#ifndef TYPEDEF_PBALL_DECLARED_
#define TYPEDEF_PBALL_DECLARED_
typedef void *PBALL ;
#endif
Now it's working in both environments. I'll leave this open for a little while in case there is a better solution than having to declare typedef twice in two header files.
I don't know what precisely is the problem, but I might be able to tell you how to figure it out.
Build your program as usual. Capture the command line of the failing compilation step. This might be something like:
gcc -c -o foo/bar.o baz.c
So baz.c presumably #includes the "bad" header files. And you get the compilation error. Now, track it down by just preprocessing your sources:
gcc -E -o foo/bar.c baz.c
-E being the option to stop after preprocessing, before actual compilation. Now try to compile the preprocessed file:
gcc -c -o foo/bar.o bar.c
You should find a similar error as before. Now look at the preprocessed source in bar.c from step 2 and you might easier find the cause. Start with just searching for the identifier that the compiler is complaining about--is it in fact declared multiple times? If so, why? Could it be in another header? Or perhaps there is a #define somewhere that is messing with your names?

Create a valid shared library in C

I'm doing some test to learn how to create shared library.
The template for shared libraries in Code::Blocks is this
library.c
// The functions contained in this file are pretty dummy
// and are included only as a placeholder. Nevertheless,
// they *will* get included in the shared library if you
// don't remove them :)
//
// Obviously, you 'll have to write yourself the super-duper
// functions to include in the resulting library...
// Also, it's not necessary to write every function in this file.
// Feel free to add more files in this project. They will be
// included in the resulting library.
// A function adding two integers and returning the result
int SampleAddInt(int i1, int i2)
{
return i1 + i2;
}
// A function doing nothing ;)
void SampleFunction1()
{
// insert code here
}
// A function always returning zero
int SampleFunction2()
{
// insert code here
return 0;
}
I tried to compile it, and it compiled without any error or warning. But when i tried to use it with the ctyped.cdll.LoadLibrary("library path.dll") in python 3(that actually should work like the C function), it said that it wasn't a valid win32 application. Both python and code::blocks are 32 bit (code:blocks compile with gcc, and i tryed to use an installed version of mingw on my system, but it gives some error about a missing library) while i'm working on win 7 64bit
Do you know what the problem can be, or if i'm doing something wrong?
EDIT1:
i'm on windows 7 64bit, in the specs file of the compiler is wrote: "Thread model: win32, gcc version 3.4.5 (mingw-vista special r3)"
and i used as command
gcc.exe -shared -o library.dll library.c
in python i used
from ctypes import *
lib = cdll.LoadLibrary("C:\\Users\\Francesco\\Desktop\\C programmi\\Python\\Ctypes DLL\\library.dll")
and the error was
WindowsError: [Error 193] %1 is not a valid Win32 application
i installed both python3.1 and mingw from the binary package and not compiling them on my system
EDIT2:
After reading Marc answer.
main.h
#ifndef __MAIN_H__
#define __MAIN_H__
#include <windows.h>
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
DLL_EXPORT int MySimpleSum(int A, int B);
#ifdef __cplusplus
}
#endif
#endif // __MAIN_H__
main.c
#include "main.h"
// a sample exported function
DLL_EXPORT int MySimpleSum(int A, int B)
{
return A+B;
}
compiling options
gcc -c _DBUILD_DLL main.c
gcc -shared -o library.dll main.o -Wl,--out-implib,liblibrary.a
with gcc 4.5.2
still get the same error..
I believe in the windows environment you need to use the __declspec annotation. How to create a shared library and the use of __declspec is described here: DLL Creation in MingW.

Resources