i have a c file named main.c
#include <stdio.h>
extern int main(int argc, char* argv[], char* envp[]);
void start(){
...;
int return_code = main(argc, argv, envp);
exit(return_code);
}
you can see I declared main but when using ld to link it:
$ (use ld to link, I didn't write it down because it's quite verbose and irrelevant)
ld: bin/test.o: in function `start':
/home/user/Desktop/test/test.c:28: undefined reference to `main'
make: *** [Makefile:49: link] Error 1
so what should i do (sorry if this is a simple question for you)
In C you have to define a main function that will be called automatically by your program, this is the base of your code.
I saw that you include "stdio.h" which is a library allowing to have access to some function like for example in my program the function "printf".
If you don't need it then don't include it :)
For example here is how to make your first program with a main function.
#include <stdio.h>
int main(int argc, char *argv[]){
... // Your code
printf("Hello world"); // Just print on your terminal this string
return (0); // 0 is the default return code if there is no errors
}
Generally speaking, invoking ld yourself is being a glutton for punishment. Use your C compiler to link until proven otherwise.
gcc -o bin/test bin/test.o will link a C program for you.
It looks like you tried to "fix" it by providing _start yourself. You can't (in C). _start is not a function.
Related
I was doing a research into the contents of another StackOverflow question and I thought it was a good time to brush up my knowledge of unix system calls.
While experimenting with execvp (WITHOUT fork on purpose) I ran into something that confuses me
I wrote 4 test programs
Program 1
#include <stdio.h>
int main() {
//printf("Doge\n");
execvp("ls");
printf("Foo\n");
return 0;
}
The program works as expected, the contents of the directory are printed and the Foo print statement is not
Program 2
However when I uncomment the first print statement and have the program be this
#include <stdio.h>
int main() {
printf("Doge\n");
execvp("ls");
printf("Foo\n");
return 0;
}
execvp returns a -1 and both print statements are issued. why?
Program 3
I vaguely remember having to use unistd.h when experimenting with unix system calls from college.
So I included it, but not execvp has a different signature and it needed some more args than just the name of the program. So I did this
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Doge\n");
char *const parmList[] = {"ls", NULL};
execvp("ls", parmList);
printf("Foo\n");
return 0;
}
And this works. This has confused me. Why did exec work in the first program?
I also used This as a reference to the system calls.
Finally I wrote
Program 4
#include <stdio.h>
//#include <unistd.h>
int main() {
printf("Doge\n");
char *const parmList[] = {"ls", NULL};
execvp("ls", parmList);
printf("Foo\n");
return 0;
}
Which also works as expected.
Can someone explain what's going on?
With this snippet
#include <stdio.h>
int main() {
execvp("ls");
printf("Foo\n");
return 0;
}
you're invoking undefined behaviour. You're not providing the prototype for execvp which requires an argument list (null terminated) as a second parameter.
Using gcc without any warning option silently uses execvp as implicitly declared, and doesn't check parameters. It just calls the function. The function then looks for a second parameter and encounters... whatever is left of the call stack (or registers, depending on call conventions), that's why a previous printf call can change the behaviour.
Using gcc -Wall gives the following warning:
test.c:5:9: warning: implicit declaration of function 'execvp' [-Wimplicit-function-declaration]
execvp("ls");
Including the proper include (#include <unistd.h>) leads to:
test.c:6:9: error: too few arguments to function 'execvp'
execvp("ls");
^~~~~~
That's why you've got strange behaviour. Don't look further. Use execvp with 2 arguments, period. In your case "Program 3" is the way to go, and always set warning level to the maximum, if possible (gcc and clang: -Wall -Wextra -pedantic -Werror)
I am exploring some adventurous ideas.
TL:DR; gnumake is able to use loadable modules, I am trying to use that C barrier to use OCaml but have trouble with the OCaml runtime initializing.
I have this OCaml code:
(* This is speak_ocaml.ml *)
let do_speak () =
print_endline "This called from OCaml!!";
flush stdout;
"Some return value from OCaml"
let () =
Callback.register "speak" do_speak
and I also have this C code: (Yes, needs to use extra CAML macros but not relevant here)
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <gnumake.h>
#include <caml/mlvalues.h>
#include <caml/callback.h>
#include <caml/memory.h>
#include <caml/alloc.h>
int plugin_is_GPL_compatible;
char *ocaml_speaker(const char *func_name, int argc, char **argv)
{
char *answer =
String_val(caml_callback(*caml_named_value("speak"), Val_unit));
printf("Speaking and got: %s\n", answer);
char *buf = gmk_alloc(strlen(answer) + 1);
strcpy(buf, answer);
/* receive_arg */
return buf;
}
int do_speak_gmk_setup()
{
printf("Getting Called by Make\n");
// This is pretty critical, will explain below
char **argv = {"/home/Edgar/foo", NULL};
caml_startup(argv);
printf("Called caml_startup\n");
gmk_add_function("speak", ocaml_speaker, 1, (unsigned int)1, 1);
return 1;
}
and I'm compiling it with this Makefile
all:
ocamlopt -c speak_ocaml.ml
ocamlopt -output-obj -o caml_code.o speak_ocaml.cmx
clang -I`ocamlc -where` -c do_speak.c -o do_speak.o
clang -shared -undefined dynamic_lookup -fPIC -L`ocamlc -where` -ldl \
-lasmrun do_speak.o caml_code.o -o do_speak.so
show_off:
echo "Speaker?"
${speak 123}
clean:
#rm -rf *.{cmi,cmt,cmi,cmx,o,cmo,so}
And my problem is that only printf("Getting Called by Make\n"); is going off when I add the appropriate load do_speak.so in the Makefile, caml_startup is not going off correctly. Now I am calling caml_startup because if I don't then I get an error of
Makefile:9: dlopen(do_speak.so, 9): Symbol not found: _caml_atom_table
Referenced from: do_speak.so
Expected in: flat namespace
in do_speak.so
Makefile:9: *** do_speak.so: failed to load. Stop.
And this is because of the way that clang on OS X does linking, see here for more details: http://psellos.com/2014/10/2014.10.atom-table-undef.html
I am kind of out of ideas... I need to create a C shared library out of OCaml code which then needs to be part of another C shared library from which I obviously don't have the original argv pointers that caml_startup wants. As my code sample show, I've tried faking it out, and also used caml_startup(NULL) and char **argv = {NULL}; caml_startup(argv) with similar lack of success. I don't know how else to initialize the runtime correctly.
I actually can't tell very well what you're asking. However, here's a comment on this part of your question:
I've tried faking it out, and also used caml_startup(NULL) and char **argv = {NULL}; caml_startup(argv) with similar lack of success. I don't know how else to initialize the runtime correctly.
As far as I know, the only reason for the argv argument of caml_startup is to establish the command-line arguments (for Sys.argv). If you don't need command-line arguments it should be OK to call like this:
char *arg = NULL;
caml_startup(&arg);
Technically argv is supposed to contain at least one string (the name of the program). So maybe it would be better to call like this:
char *argv[] = { "program", NULL };
caml_startup(argv);
I'm trying to compile third party source code using gcc 4.8 on Ubuntu Linux (12.04 x64) with a lot of utilities and test applications where executable entry point is not called main. Don't ask me why - I don't know the answer.
Linker of course complains:
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Is it possible to force linker to use another method as the entry point? I tried to use these linker options with gcc but neither of them worked:
-Wl,-eWhatever or -Wl,--entry=Whatever or -Wl,-e,Whatever. All ended with the same error.
As by C Standard, the hosted environment (that I guess is your case as/if you want to use standard library headers*) forces you to keep with main function. From C11 §5.1.2.2.1/p1 (emphasis mine):
The function called at program startup is named main. The
implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as
argc and argv, though any names may be used, as they are local to the
function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;10) or in some other
implementation-defined manner.
There are two options that I can think of to bypass main function requirement in your situation:
Create separate object file (that is, by gcc -c) with main symbol, that just (declares and) calls (i.e. wraps) your custom entry point (possibly passing through argc and argv invocation arguments). This would make linker happy and is as simple as adding single makefile rule.
Compile your program as gcc -DWhatever=main. This essentially replaces every instance of Whatever preprocessing token by main, so linker thinks of Whatever as "proper" main function.
* some headers must be available in freestanding environment too, such as <stddef.h> and <float.h>, see §4/p6 for full list of them.
Here is some basic ilustration of both options. Each assumes, that foo.c is as following:
foo.c
#include <stdio.h>
void foo(void)
{
printf("foo\n");
}
First method:
main.c
/* declare an entry point */
void foo(void);
/* define main as wrapper function */
int main(void)
{
foo();
return 0;
}
Compile & run:
$ gcc -c main.c
$ gcc foo.c main.o
$ ./a.out
foo
Second method:
$ gcc -Dfoo=main foo.c
$ ./a.out
foo
Some things may require more tweaking, but I hope you catch the idea.
I am trying to use the 'environ' variable, but it keeps giving me an error. It seems to be a makefile/build error and I can't seem to fix it. I have searched fo answers, but still I am lost.
Here is my c file:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include "cmd.h"
int cmdExec() {
...
extern char **environ;
...
printf("Enter a command\n");
//gets (input);
scanf("%s%*[^\n]", input);
if (...) {
...
}
else if (strcmp(input, "environ") == 0) {
int i;
for (i = 0; environ[i] != NULL; i++) {
printf("%s\n", environ[i]);
}
exit(0);
else
...
return 0;
}
and here is the makefile:
CC = gcc
CFLAGS = -c
CFLAGS-y = -std=c99
all: cmd
cmd.o: cmd.c cmd.h
$(CC) $(CFLAGS) $(CFLAGS-y) cmd.c
cmd.exe: cmd.o
$(CC) -o cmd.exe cmd.o
clean:
rm -rf *.o cmd.exe a.out
This is the output:
make all
gcc -c -std=c99 cmd.c
gcc cmd.o -o cmd
cmd.o:cmd.c:(.text+0x105): undefined reference to `environ'
cmd.o:cmd.c:(.text+0x127): undefined reference to `environ'
collect2: ld returned 1 exit status
make: *** [cmd] Error 1
From what I've searched this deals with linking libraries, but I don't know how to apply that to my specific situation. If someone could give me a hand I'd appreciate it.
Not all(if any) compilers on Windows provides access to environment variables through a global symbol named environ.
You can use e.g. getenv() to access environment variables.
The win32 API provides GetEnvironmentStrings() to access all the variables.
Some platforms allow you to access the environment through an additional argument to main(), you'd declare your main function as:
int main(int argc, char *argv[], char *environ[])
The environ global variable is defined by POSIX, and is not supported by Windows (unless you're using Cygwin, which is a POSIX-like layer implemented on top of Windows).
As far as I know, the non-standard definition
int main(int argc, char **argv, char **envp) { /* ... */ }
is also not supported on Windows.
But a quick Google search turned up this answer, which points to the documentation for the Windows-specific GetEnvironmentStrings function:
LPTCH WINAPI GetEnvironmentStrings(void);
If the function succeeds, the return value is a pointer to the
environment block of the current process.
If the function fails, the return value is NULL.
The result points to a long string with the environment variables separated by '\0' null characters, with the environment terminated by two consecutive null characters.
LPTCH is Microsoft's typedef for a pointer to either unsigned char or a 16-bit wchar_t. See the referenced documentation for more information.
I am working from a book: TCP/IP Sockets in C and its website code.
I am trying to build a client and server based on those files. My make gives lots of
error related to not being able to find functions from DieWithMessage.c
Here it is:
#include <stdio.h>
#include <stdlib.h>
#include "Practical.h"
void DieWithUserMessage(const char *msg, const char *detail) {
fputs(msg, stderr);
fputs(": ", stderr);
fputs(detail, stderr);
fputc('\n', stderr);
exit(1);
}
void DieWithSystemMessage(const char *msg) {
perror(msg);
exit(1);
}
When I do gcc DieWithMessage.c, I get the following error:
/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5.2/../../../crt1.o: In function _start':
(.text+0x18): undefined reference tomain'
collect2: ld returned 1 exit status
How do I compile this by itself so that the errors will stop happening when using the makefile?
Thanks for any help.
Your C code needs a main function if you're going to try an link/run it. This is a requirement for hosted C applications under the standard.
That error message indicates what's wrong. The C runtime/startup code (CRT) has an entry point of start which sets up the environment then calls your main. Since you haven't provided a main, it complains.
If you only want to generate an object file for later linking with a main (see here for one description of the process), use something like:
gcc -c -o DieWithMessage.o DieWithMessage.c
(-c is the "compile but don't link" flag). You can then link it later with your main program with something like (although there are other options):
gcc -o myProg myProg.c DieWithMessage.o
If you want a placeholder main to update later with a real one, you can add the following to your code:
int main (void) { return 0; }