LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   compiling C code (https://www.linuxquestions.org/questions/programming-9/compiling-c-code-237118/)

Stranger 10-06-2004 03:04 PM

As a thought experiment, I tried the following:

In foo.c _
Code:

int baz();

int foo()
{
        return baz();
}

In bar.c _
Code:

int baz();

int bar()
{
        return baz();
}

In baz.c _
Code:

int baz()
{
        return RESULT;
}

In main.c _
Code:

#include <stdio.h>

int bar();
int foo();

int main(void)
{
        printf("foo %d\n", foo());
        printf("bar %d\n", bar());
}

To build the beast _

Code:

gcc -c foo.c
gcc -c bar.c
gcc -o baz1.o -DRESULT=1 -c baz.c
gcc -o baz2.o -DRESULT=2 -c baz.c
ar rcs libb.a foo.o baz1.o
ar rcs libf.a bar.o baz2.o
gcc --static main.c -L. -lb -lf -o main

When I ran ./main, you can guess what it gave me:

Quote:

foo 1
bar 1
Unless I missed something, the last invocation of gcc links only one copy of baz().

Sorry, Charlie.

vose 10-06-2004 03:21 PM

I also can think of many things which do not work!
Hence my question: what does work?

I can certainly write code/scripts which will temporarily change
baz.c so that it's functions are static, and then proceed along the
lines of scenerio one (with includes, etc...), after which baz.c is
restored... That approach does work.

But if there are standard tools which could do the job (with
appropriate flags perhaps) then I would like to know about them
and how they are used to accomplish what otherwise I would
have to write code/scripts for.

Stranger 10-06-2004 03:22 PM

Of course, changing the build script to _

Code:

gcc -c foo.c
gcc -c bar.c
gcc -o baz1.o -DRESULT=1 -c baz.c
gcc -o baz2.o -DRESULT=2 -c baz.c
ld -o f.o foo.o baz1.o
ld -o b.o bar.o baz2.o
gcc -o main main.c f.o b.o

gives us _

Quote:

ld: warning: cannot find entry symbol _start; defaulting to 00000000080480b4
ld: warning: cannot find entry symbol _start; defaulting to 00000000080480b4
b.o(.text+0x10): In function `baz':
: multiple definition of `baz'
f.o(.text+0x10): first defined here
collect2: ld returned 1 exit status
Sorry, Charlie.

Unless I've missed something, I think you'd have to do as I suggested previously, and use macro templates to generate functions with different names for your -Dmacro=def. I know it's not what you wanted-and I may have missed something-I'm no expert, by far-but let's use the tools to do as their designers designed them to work.

vose 10-06-2004 03:30 PM

Again, you have provided something which does not work.
I also can produce many examples of things which do not work.
That is not the point.

Stranger 10-06-2004 03:35 PM

Quote:

I also can think of many things which do not work!
Hence my question: what does work?
By going through things which won't work and giving my interpretation of why they don't work, I'm wondering if one of us will think of something that WILL work.

Your pretend build process _

Quote:

...
d --output=f.o --relocateable --MAKE_STATIC_ALL_FUNCTIONS_IN_FILE=myfile foo.o baz1.o
ld --output=b.o --relocateable --MAKE_STATIC_ALL_FUNCTIONS_IN_FILE=myfile bar.o baz2.o
...
tries to make functions static when you defined them as non-static. Obviously, the developers of ld either hadn't anticipated this use or decided for one reason or another not to implement it (unless you can find a flag that works as you want it to function).

In order to accomplish what you want, our tool would have to remove the symbols that you don't want the linker to see from the symbol table. I played with LFS for a day or so, and I recall that when you wanted to change the libraries with which the tool chain would work, you would awk one of the shared objects to change an entry. Now, obviously these shared libraries were no more than lists of library names, but it might give you ideas.

I don't recall seeing such a tool that would selectively remove entries from the symbol table of an object file.

Sorry, Charlie.

Stranger 10-06-2004 03:55 PM

Quote:

Originally posted by vose
Again, you have provided something which does not work.
I also can produce many examples of things which do not work.
That is not the point.

Oh, give me a break. I'm looking at this as a puzzle, and it intrigues me. You asked the question, and I've attempted to find a solution. Have you given any feedback to my experiments, other than complain that I haven't given you the answer? Go cry to your mama, or come up with a better way to solve the problem.

I suggested template macros. It sounded like an elegant solution to me. I even suggested it twice. You gave me no feedback.

You suggested a script to alter the code, but you want an alternative.

If you've looked for a tool to do what you want to do and haven't found it, and you think you've looked in all the right places and feel that you won't find it, write the tool. I told you what the tool needs to do. Sure I haven't delved into all of the details-and I don't know all of the details by rote-but I think my explanation sums it up.

Put up or shut up. Someone is interested in finding the same solution that you want to find. I would think that you would welcome it. But NO! All I get from you is that you could make as many mistakes trying to find an answer. Well, LA-TI-FREAKING-DA. So what?

I give up.

Tinkster 10-06-2004 04:21 PM

Come on girls, play nice.

vose: you're not paying anyone here, so stop whining,
he has the right to add ideas even if they don't do what
you expect.

stranger: if you don't like him (or his attitude), don't post
to his thread. No accusations.


Cheers,
Tink

Stranger 10-06-2004 05:52 PM

Tinkster: I apologize for my outburst. But.... Oh, nevermind. :) Back to our program.

baz.h

Code:

#define BAZ(R) \
int baz##R() \
{ \
        return R; \
}

#if RESULT == 1
#define baz baz##1
#elif RESULT == 2
#define baz baz##2
#endif

baz.c

Code:

#include "baz.h"

#if RESULT == 1
BAZ(1)
#elif RESULT == 2
BAZ(2)
#endif

foo.c

Code:

#include "baz.h"

int foo()
{
        return baz();
}

bar.c

Code:

#include "baz.h"

int bar()
{
        return baz();
}

main.c

Code:

#include <stdio.h>

int bar();
int foo();

int main(void)
{
        printf("foo %d\n", foo());
        printf("bar %d\n", bar());
}

build

Code:

gcc -c -DRESULT=1 foo.c
gcc -c -DRESULT=2 bar.c
gcc -o baz1.o -DRESULT=1 -c baz.c
gcc -o baz2.o -DRESULT=2 -c baz.c
gcc -o main main.c foo.o baz1.o bar.o baz2.o

Code:

$ ./main
foo 1
bar 2
$

Good = fast + correct. You implied that you're comfortable with macros. It would require almost zero maintenance. And it works. :D

By the way, debugging might prove difficult. :rolleyes:

vose 10-06-2004 07:28 PM

Your last post has caught up to my question.

But I am not attempting to resolve name conflicts
by redefining foo.c and bar.c as in

gcc -c -DRESULT=1 foo.c
gcc -c -DRESULT=2 bar.c

in order to create new names, so as to then create matching names
in baz.c by

gcc -o baz1.o -DRESULT=1 -c baz.c
gcc -o baz2.o -DRESULT=2 -c baz.c

Instead, I hope to leave foo.c, bar.c, and baz.c *alone* so that I
don't have to rewrite them or make them any more complicated
than they already are.

My intent -- and the point of my question -- is indicated fairly well
by the "pretend" answer

gcc -c foo.c
gcc -c bar.c
gcc -Dmacro=def1 -o baz1.o -c baz.c
gcc -Dmacro=def2 -o baz2.o -c baz.c
ld --output=f.o --relocateable --MAKE_STATIC_ALL_FUNCTIONS_IN_FILE=myfile foo.o baz1.o
ld --output=b.o --relocateable --MAKE_STATIC_ALL_FUNCTIONS_IN_FILE=myfile bar.o baz2.o
gcc -o a.out f.o b.o

I realize that the above does not work, BUT, I am well aware of my ingorance as
to what compilation/linking tools there are. And even if I were cognizant of all
available compilation/linking tools, I certainly would not believe I knew every way
they might be used.

Whereas I most certainly could be wrong as to whether there infact do exist some
tool(s) (like ld, or gcc, or ???) which if provided appropriate arguments (and flags)
would be able to produce an a.out as in senerio one given foo.c, bar.c and baz.c
as in scenerio two---see my original question---it nevertheless seemed plausible
to me that such tool(s) might exist.

Therefore, my question is: what are those tools, and how would I use
them to accomplish that objective?

There could be no better answer (to the question I seek to have answered) than
to simply write code/scripts which will temporarily change baz.c so that it's
functions are static, and then proceed along the lines of scenerio one (with
includes, etc...), after which baz.c is restored... However, for all I know, there
*is* (which is why I asked).

Stranger 10-06-2004 07:41 PM

Code:

#if LINKAGE == 0
#define QUICKFIX static
#else
#define QUICKFIX
#endif

...

QUICKFIX void function_name(int param1) {
...
}

...

Code:

gcc -DLINKAGE=0 -c baz.c
Do you really need a script to do this?

vose 10-06-2004 07:53 PM

Yes!!! That answer is so simple and beautiful I did not see it.

It is now a more academic question, but one which nevertheless
interests me, namely, whether standard compilation/linking tools
could also do the job.

P.S. The last paragraph is not intended to diminish your reply.
Your answer may very well be as perfect as is possible!

Stranger 10-06-2004 08:21 PM

Ah! But your compiler does do the job! You just use the source and a command-line option to tell it what to do.

I also noticed a particular flag in ld's man page that looks useful for this situation. I just haven't figured out how.

Quote:

-R filename
--just-symbols=filename
Read symbol names and their addresses from filename, but do not relocate it or include it in the output. This allows your output file to refer symbolically to absolute locations of memory defined in other programs. You may use this option more than once. For compatibility with other ELF linkers, if the -R option is followed by a directory name, rather than a file name, it is treated as the -rpath option.
I don't know if it's at all useful.

Stranger 10-06-2004 08:42 PM

You could even simplify the above example even further.

Code:

#if defined(LINKAGE)
#define QUICKFIX static
#else
#define QUICKFIX
#endif

...

QUICKFIX void function_name(int param1) {
...
}

...

Code:

gcc -DLINKAGE=1 -c baz.c

or

gcc -c baz.c


WhiteChedda 10-07-2004 05:57 AM

Would using a function pointer within each source, change the way the compiler resolved the symbols at all?

vose 10-08-2004 07:28 AM

I don't know, and whereas what I have to say below does not answer your question, it does
fill out to some extent the context of this thread to make things a bit less abstract.
My hope is that by my doing so, readers of this thread may come away with some useful
programming ideas.

First, foo and bar can be generalized to foo, bar-1, bar-2, .... That was the context of
our actual application. Foo was the "master thread" and threads bar-1, bar-2,... were
helper threads running on different processors of a smp gnu/linux system.

The point of the code was to simulate a complex stochastic system. However, having every
thread obtain it's random number stream from a single source lead to debugging problems
since race conditions caused unrepeatable behavior (by single source I mean that each
thread would call the same random number generator; in some sense, of course, these are
"different" generators since each call uses the stack of the calling thread). Debugging aside,
race conditions trashed repeatability.

The simplest answer was to move a copy of the random generator into each thread such that
each thread maintains a separate and independent copy of the random number generator's
state. How to do this without changing the code?!? And we did NOT want to change
the code for at least the reasons that:
1) The better half of the staff would walk out the door if asked to put up with C++ bullshit.
2) Speed mattered, and passing the state as an argument would slow things down.
3) Simplicity was a concern; we did not want to make anything Except Maybe The Make File
more complicated than it already was.
4) We wanted to keep a single simple source file for the generator.
5) We wanted to preserve the accumulated experience with debugging in terms of what
names, variables, etc., one encounters/manipulates during a debugging session.

The method of changing the build (as indicated in the posts to this thread) satisfied all our
criteria and solved our repeatability problems, with the added benefit that the independent
builds of our random generator (i.e., baz) allowed us to independently instanciate the
semantics of each thread's random stream as well.

Happy Hacking.
Vose


All times are GMT -5. The time now is 08:54 AM.