Hello and thank you for your assistance.
I'm attempting to create a simple 'hello world' using only low-level OS X kernel calls to allocate memory and write out to stdout. Why? I'm finishing up chapter 8 of 2nd Edition K&R which is focused on writing standard file library from scratch. It is, of course, totally out of date but the concept of the chapter remains. Anyway, I cannot seem to figure out how to properly link to get everything to work out and are thus earning myself lots of nice undefined symbol errors.
I have parsed through many other questions causing the same error, but have not found any that address how to link in the kernel library I'm attempting to use. The crazy long path in the third #include was needed to just get the thing to compile even prior to the link errors.
The Code:
#include <fcntl.h>
#include <unistd.h> // equivalent to (K&R) #include "syscalls.h"
#include </Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/libkern/OSMalloc.h> // for low-level memory allocation
#define MINSTDIOTAG "com.apple.minstdio" // Used by OSMalloc from <libkern/OSMalloc.h>
#define PAGE_SIZE_64K (64 * 1024) // Page size to allocate
int main(void) {
char *base = NULL; // Memory buffer
char *ptr = base; // Location in buffer
// Create tag
OSMallocTag mytag = OSMalloc_Tagalloc(MINSTDIOTAG, OSMT_DEFAULT);
// Attempt to allocate PAGE_SIZE_64K of memory
if ((base = (char *)OSMalloc(PAGE_SIZE_64K, mytag)) == NULL)
return 1;
ptr = base;
// Stuff the buffer with stuff
*ptr++ = 'f';
*ptr++ = 'o';
*ptr++ = 'o';
*ptr++ = '\n';
*ptr = '\0';
// Write it out to stdout
(void)write(STDOUT_FILENO, base, (size_t)(ptr - base));
// Free allocated memory
OSFree(base, PAGE_SIZE_64K, mytag);
// Get out of Dodge City, Kansas
return 0;
}
Makefile:
BIN = ../../bin
ODIR = obj
CC = cc
CFLAGS = -std=c99 -Wall -g -I.
_OBJ = minstdio3.o
_BIN = minstdio3
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
.PHONY: all clean
all: $(_BIN)
clean:
rm -rv $(ODIR) $(_BIN)
minstdio3: $(ODIR)/minstdio3.o
$(CC) $(CFLAGS) $^ -o $#
cp -v $# $(BIN)/$#
$(ODIR)/%.o: %.c $(DEPS)
mkdir -pv $(ODIR)
$(CC) $(CFLAGS) -c -o $# $<
Errors Received:
Todds-MBP-2:cbasics todddecker$ make
mkdir -pv obj
cc -std=c99 -Wall -g -I. -c -o obj/minstdio3.o minstdio3.c
cc -std=c99 -Wall -g -I. obj/minstdio3.o -o minstdio3
Undefined symbols for architecture x86_64:
"_OSFree", referenced from:
_main in minstdio3.o
"_OSMalloc", referenced from:
_main in minstdio3.o
"_OSMalloc_Tagalloc", referenced from:
_main in minstdio3.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [minstdio3] Error 1
-- EDITS --
"Why are you not using the sbrk system call if you want low-level? This would match your use of write and shouldn't give any linking issues." (from CRD)
Using 'sbrk' (and it's cousin 'brk') was the original path I was headed down; however, the man page for 'sbrk' states, "The brk and sbrk functions are historical curiosities left over from earlier days before the advent of virtual memory management." This statement put me on a path toward trying to discover its replacement. 'malloc' is, of course, the correct and normal utility for memory allocation. However, K&R Chapter 8 is all about writing your own from base OS system calls. So, the base call I was able to find for OS X Darwin is 'OSMalloc' which I'm trying to use.
OSMalloc is only available for writing the kernel itself (kernel extensions, device drivers). User programs have to use sbrk.
Related
I have simplified the code to the minimum
#include "frozen.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
int main()
{
char *json = "{ \"a\": 123, \"b\": \"hi\", c: true }";
int value = 0;
json_scanf(json, strlen(json), "{c: %B}", &value);
printf("Hello World\n");
// assert( json != NULL );
printf( "json: %s\n", json );
printf( "json.c: %s\n", value );
// free( json );
return 0;
}
directory structure:
/home/projects/json-test/main.c
/home/projects/json-test/frozen/{contents of https://github.com/cesanta/frozen repo}
What I do:
gcc main.c -Ifrozen -o main
What is being displayed in output:
main /tmp/ccsYWNAP.o: In function `main': main.c:(.text+0x43):
undefined reference to `json_scanf' collect2: error: ld returned 1
exit status
I have very limited knowledge in C, thus I may be missing some steps, so take into account that I literally did not do anything else than written above, maybe I should have. I am used to loosely typed php/js/python kind of languages, but I was reading that just including file does not tell gcc that "you should search for json_scanf inside frozen.h". Should there be some sort of a "glue", or "linking" step I am missing?
UPDATE: Based on responses, I have created this Makefile:
CC = gcc
FLAGS = -std=c99
DEST_DIR = ./bin
DEST_PATH = "$(DEST_DIR)/main"
BUILD_DIR = ./build
all: clean directories json main.o
$(CC) $(BUILD_DIR)/*.o -o $(DEST_PATH) $(FLAGS)
main.o: src/main.c $(BUILD_DIR)/frozen.o
$(CC) src/main.c -c -o $(BUILD_DIR)/main.o $(FLAGS)
json: json.o
json.o: src/frozen/frozen.c src/frozen/frozen.h
$(CC) src/frozen/frozen.c -c -o $(BUILD_DIR)/frozen.o $(FLAGS)
clean:
rm -rf $(BUILD_DIR)
directories:
mkdir -p $(DEST_DIR)/
mkdir -p $(BUILD_DIR)/
And changing #include "frozen.h" to #include "frozen/frozen.h", and running make, creates build/main file that can be successfully ran with ./bin/main command. Thank you!
Ugh. You don't have a mistake. The library developer has some really bad coding practices. Basically, for whatever reason, his header is not sufficient for compilation. If you look at the unit_test.c in the repository of frozen, you will see he's actually including frozen.c instead of frozen.h. If you change your #include "frozen.h" to #include "frozen.c" it will work fine. The other option is to provide the .c file explicitly:
gcc frozen/frozen.c main.c -Ifrozen
Normally, you'd put everything in the header, or require the library to be compiled, as a .a file and then linked when you use it, but he hasn't provided a makefile that does that.
EDIT: You can also compile frozen.o beforehand, but the library's author should've really provided a makefile to do that...
gcc -c frozen.c -o ../frozen.o
cd ..
gcc main.c frozen.o -Ifrozen
I am trying to create a static library and link it on MacOS X (several versions):
File foo.c:
char foo[111];
File bar.c:
#include <string.h>
extern char foo[];
int bar(char *src) {
strcpy(foo, src);
return strlen(foo);
}
Create a library:
$ cc -c foo.c bar.c
$ ar r libfoobar.a foo.o bar.o
ar: creating archive libfoobar.a
$ ranlib libfoobar.a
$ nm libfoobar.a
libfoobar.a(foo.o):
000000000000006f C _foo
libfoobar.a(bar.o):
U ___strcpy_chk
0000000000000000 T _bar
U _foo
U _strlen
Create a small test program:
File main.c:
#include <stdio.h>
int bar(char *);
int main(void) {
printf("foobarbar = %i\n", bar("123"));
return 0;
}
Compile and link:
$ cc -c main.c
$ cc -o m main.o -L. -lfoobar
Undefined symbols for architecture x86_64:
"_foo", referenced from:
_bar in libfoobar.a(bar.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Why is the symbol not found? It is defined in foo.c? Shouldn't at least ranlib create an index in the library that allows a random order of the files there?
The same code works well under Linux (gcc), and also when the symbol in foo.c is not a char array, but an int.
There is a similar question: Object files not properly added to archive on mac which has this answer:
Option 1:
ar -rs my_archive.a foo.o bar.o other_object_files.o
ranlib -c my_archive.a
Option 2:
libtool -c -static -o my_archive.a foo.o bar.o other_object_files.o
It is -c flag that makes a difference for both options on ranlib and libtool respectively:
-c
Include common symbols as definitions with respect to the table
of contents. This is seldom the intended behavior for linking
from a library, as it forces the linking of a library member
just because it uses an uninitialized global that is undefined
at that point in the linking. This option is included only
because this was the original behavior of ranlib. This option
is not the default.
as a continuation to this post C pluginsystem: symbol lookup error, I am still writing my plugin system and encounter new bugs.
To recap what the plugins are, the program consists of a network application interfaced by a shell, messages has a type and therefore can be use to create applications on the network. For exemple, a possible application would be a chat or a transfert application.
So shell commands can send message of a particular application on the network, when a message is received, if it corresponds to a particular application then an action function is executed with the message content as argument, it could be the application.
A plugin is a shared library with an init function that register it's commands and actions. A command could just be a simple command that doesn't interact with the network, and that's why I achieved at the moment.
The plugin system consists in modules:
plugin_system.c
list.c used by the first module to store plugins
The network part consists in:
protocol.c main part of the protocol
message.c main part for message treatment
application.c main part used to program applications
common.c file with ccommon functions
network.c useful network functions
The modules in protocole are all interdependent, I have split files for conveniency.
All modules are compiled with -fPIC option.
To compile a plugin called plug.c wich doesn't interact with the network, I use:
gcc -Wall -O2 -std=gnu99 -D DEBUG -g -fPIC -c -o plug.o plug.c
gcc -Wall -O2 -std=gnu99 -D DEBUG -g -o plug.so plug.o plugin_system.o list.o -shared
And it works perfectly, the library is loaded with dlopen with no problem, the init function loaded with dlsym and executed correctly so the plugin is registered, I then executed the command and I can see that it work.
Now I wan't to add supports for network communications for the plugins, so I have modified the same test plugin that I used which has just a command to print a message. I have had a call to sendappmessage_all a function that send a message to everyone over the network, defined in message.c.
I can compile the new plugin without adding the network module objects, it compile, the plugin loads correctly, but when it call sendappmessage_all obviously it fails with the message
symbol lookup error: ./plugins/zyva.so: undefined symbol: sendappmessage_all
So to make it work, I should like the plugin with network modules so that's what I have done with
gcc -Wall -O2 -std=gnu99 -D DEBUG -g -o plug.so plug.o plugin_system.o list.o protocol.o message.o thread.o common.o application.o network.o -shared
It compile but when I try to load the plugin, dlopen return NULL.
I have also tried to add just one module, at worst it would only result in an undefined symbol error, but I dlopen still return NULL.
I know it's a lot of informations and on the otherside you probably wan't to see the code but I tried to be the clearer in the most succint way I could be because is way more complex and bigger than the post.
Thank you for your understanding.
The problem is that when you compile the plugin system (i.e. functions called by plugins), and link it to the final executable, the linker does not export the symbols used by the plugins in the dynamic symbol table.
There are two options:
Use -rdynamic when linking the final executable, adding all symbols to the dynamic symbol table.
Use -Wl,-dynamic-list,plugin-system.list when linking the final executable, adding symbols listed in file plugin-system.list to the dynamic symbol table.
The file format is simple:
{
sendappmessage_all;
plugin_*;
};
In other words, you can list either each symbol name (function or data structure), or a glob pattern that matches the desired symbol names. Remember the semicolon after each symbol, and after the closing brace, or you'll get a "syntax error in dynamic list" error at link time.
Note that just marking a function "used" via __attribute__((used)) is not sufficient to make the linker include it in the dynamic symbol table (with GCC 4.8.4 and GNU ld 2.24, at least).
Since the OP thinks what I wrote above is incorrect, here is a fully verifiable proof of the above.
First, a simple main.c that loads plugin files named on the command line, and executes their const char *register_plugin(void); function. Because the function name is shared across all plugins, we need to link them locally (RTLD_LOCAL).
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <stdio.h>
static const char *load_plugin(const char *pathname)
{
const char *errmsg;
void *handle; /* We deliberately leak the handle */
const char * (*initfunc)(void);
if (!pathname || !*pathname)
return "No path specified";
dlerror();
handle = dlopen(pathname, RTLD_NOW | RTLD_LOCAL);
errmsg = dlerror();
if (errmsg)
return errmsg;
initfunc = dlsym(handle, "register_plugin");
errmsg = dlerror();
if (errmsg)
return errmsg;
return initfunc();
}
int main(int argc, char *argv[])
{
const char *errmsg;
int arg;
if (argc < 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s plugin [ plugin ... ]\n", argv[0]);
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
for (arg = 1; arg < argc; arg++) {
errmsg = load_plugin(argv[arg]);
if (errmsg) {
fflush(stdout);
fprintf(stderr, "%s: %s.\n", argv[arg], errmsg);
return EXIT_FAILURE;
}
}
fflush(stdout);
fprintf(stderr, "All plugins loaded successfully.\n");
return EXIT_SUCCESS;
}
The plugins will have access via certain functions (and/or variables), declared in plugin_system.h:
#ifndef PLUGIN_SYSTEM_H
#define PLUGIN_SYSTEM_H
extern void plugin_message(const char *);
#endif /* PLUGIN_SYSTEM_H */
They are implemented in plugin_system.c:
#include <stdio.h>
void plugin_message(const char *msg)
{
fputs(msg, stderr);
}
and listed as dynamic symbols in plugin_system.list:
{
plugin_message;
};
We'll also need a plugin, plugin_foo.c:
#include <stdlib.h>
#include "plugin_system.h"
const char *register_plugin(void) __attribute__((used));
const char *register_plugin(void)
{
plugin_message("Plugin 'foo' is here.\n");
return NULL;
}
and just to remove any confusion about what effect there is having each plugin a registration function by the same name, another plugin named plugin_bar.c:
#include <stdlib.h>
#include "plugin_system.h"
const char *register_plugin(void) __attribute__((used));
const char *register_plugin(void)
{
plugin_message("Plugin 'bar' is here.\n");
return NULL;
}
To make all of this easy to compile, we'll need a Makefile:
CC := gcc
CFLAGS := -Wall -Wextra -O2
LDFLAGS := -ldl -Wl,-dynamic-list,plugin_system.list
PLUGIN_CFLAGS := $(CFLAGS)
PLUGIN_LDFLAGS := -fPIC
PLUGINS := plugin_foo.so plugin_bar.so
PROGS := example
.phony: all clean progs plugins
all: clean progs plugins
clean:
rm -f *.o $(PLUGINS) $(PROGS)
%.so: %.c
$(CC) $(PLUGIN_CFLAGS) $^ $(PLUGIN_LDFLAGS) -shared -Wl,-soname,$# -o $#
%.o: %.c
$(CC) $(CFLAGS) -c $^
plugins: $(PLUGINS)
progs: $(PROGS)
example: main.o plugin_system.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
Note that Makefiles require intendation by tabs, not spaces; listing the file here always converts them to spaces. So, if you paste the above to a file, you'll need to fix the indentation, via e.g.
sed -e 's|^ *|\t|' -i Makefile
It is safe to run that more than once; the worst it can do, is mess up your "human-readable" layout.
Compile the above using e.g.
make
and run it via e.g.
./example ./plugin_bar.so ./plugin_foo.so
which shall output
Plugin 'bar' is here.
Plugin 'foo' is here.
All plugins loaded successfully.
to standard error.
Personally, I prefer to register my plugins via a structure, with a version number, and at least one function pointer (to the initialization function). This lets me load all plugins before initializing them, and resolve e.g. interplugin conflicts or dependencies. (In other words, I use a structure with a fixed name, rather than a function with a fixed name, to identify plugins.)
Now, as to __attribute__((used)). If you modify plugin_system.c into
#include <stdio.h>
void plugin_message(const char *msg) __attribute__((used));
void plugin_message(const char *msg)
{
fputs(msg, stderr);
}
and modify the Makefile to have LDFLAGS := -ldl only, the example program and plugins will compile just fine, but running it will yield
./plugin_bar.so: ./plugin_bar.so: undefined symbol: plugin_message.
In other words, if the API exported to plugins is compiled in a separate compilation unit, you will need to use either -rdynamic or -Wl,-dynamic-list,plugin-system.list to ensure the functions are included in the dynamic symbol table in the final executable; the used attribute does not suffice.
If you want all and only non-static functions and symbols in plugin_system.o included in dynamic symbol table in the final binary, you can e.g. modify the end of the Makefile into
example: main.o plugin_system.o
#rm -f plugin_system.list
./list_globals.sh plugin_system.o > plugin_system.list
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
with list_globals.sh:
#!/bin/sh
[ $# -ge 1 ] || exit 0
export LANG=C LC_ALL=C
IFS=:
IFS="$(printf '\t ')"
printf '{\n'
readelf -s "$#" | while read Num Value Size Type Bind Vis Ndx Name Dummy ; do
[ -n "$Name" ] || continue
if [ "$Bind:$Type" = "GLOBAL:FUNC" ]; then
printf ' %s;\n' "$Name"
elif [ "$Bind:$Type:$Ndx" = "GLOBAL:OBJECT:COM" ]; then
printf ' %s;\n' "$Name"
fi
done
printf '};\n'
Remember to make the script executable, chmod u+x list_globals.sh.
So I'm trying trying to use a function defined in another C (file1.c) file in my file (file2.c). I'm including the header of file1 (file1.h) in order to do this.
However, I keep getting the following error whenever I try to compile my file using gcc:
Undefined symbols for architecture x86_64:
"_init_filenames", referenced from:
_run_worker in cc8hoqCM.o
"_read_list", referenced from:
_run_worker in cc8hoqCM.o
ld: symbol(s) not found for architecture x86_64
I've been told I need to "link the object files together" in order to use the functions from file1 in file2, but I have no clue what that means :(
I assume you are using gcc, to simply link object files do:
$ gcc -o output file1.o file2.o
To get the object-files simply compile using
$ gcc -c file1.c
this yields file1.o and so on.
If you want to link your files to an executable do
$ gcc -o output file1.c file2.c
The existing answers already cover the "how", but I just wanted to elaborate on the "what" and "why" for others who might be wondering.
What a compiler (gcc) does: The term "compile" is a bit of an overloaded term because it is used at a high-level to mean "convert source code to a program", but more technically means to "convert source code to object code". A compiler like gcc actually performs two related, but arguably distinct functions to turn your source code into a program: compiling (as in the latter definition of turning source to object code) and linking (the process of combining the necessary object code files together into one complete executable).
The original error that you saw is technically a "linking error", and is thrown by "ld", the linker. Unlike (strict) compile-time errors, there is no reference to source code lines, as the linker is already in object space.
By default, when gcc is given source code as input, it attempts to compile each and then link them all together. As noted in the other responses, it's possible to use flags to instruct gcc to just compile first, then use the object files later to link in a separate step. This two-step process may seem unnecessary (and probably is for very small programs) but it is very important when managing a very large program, where compiling the entire project each time you make a small change would waste a considerable amount of time.
You could compile and link in one command:
gcc file1.c file2.c -o myprogram
And run with:
./myprogram
But to answer the question as asked, simply pass the object files to gcc:
gcc file1.o file2.o -o myprogram
Add foo1.c , foo2.c , foo3.c and makefile in one folder
the type make in bash
if you do not want to use the makefile, you can run the command
gcc -c foo1.c foo2.c foo3.c
then
gcc -o output foo1.o foo2.o foo3.o
foo1.c
#include <stdio.h>
#include <string.h>
void funk1();
void funk1() {
printf ("\nfunk1\n");
}
int main(void) {
char *arg2;
size_t nbytes = 100;
while ( 1 ) {
printf ("\nargv2 = %s\n" , arg2);
printf ("\n:> ");
getline (&arg2 , &nbytes , stdin);
if( strcmp (arg2 , "1\n") == 0 ) {
funk1 ();
} else if( strcmp (arg2 , "2\n") == 0 ) {
funk2 ();
} else if( strcmp (arg2 , "3\n") == 0 ) {
funk3 ();
} else if( strcmp (arg2 , "4\n") == 0 ) {
funk4 ();
} else {
funk5 ();
}
}
}
foo2.c
#include <stdio.h>
void funk2(){
printf("\nfunk2\n");
}
void funk3(){
printf("\nfunk3\n");
}
foo3.c
#include <stdio.h>
void funk4(){
printf("\nfunk4\n");
}
void funk5(){
printf("\nfunk5\n");
}
makefile
outputTest: foo1.o foo2.o foo3.o
gcc -o output foo1.o foo2.o foo3.o
make removeO
outputTest.o: foo1.c foo2.c foo3.c
gcc -c foo1.c foo2.c foo3.c
clean:
rm -f *.o output
removeO:
rm -f *.o
Since there's no mention of how to compile a .c file together with a bunch of .o files, and this comment asks for it:
where's the main.c in this answer? :/ if file1.c is the main, how do
you link it with other already compiled .o files? – Tom Brito Oct 12
'14 at 19:45
$ gcc main.c lib_obj1.o lib_obj2.o lib_objN.o -o x0rbin
Here, main.c is the C file with the main() function and the object files (*.o) are precompiled. GCC knows how to handle these together, and invokes the linker accordingly and results in a final executable, which in our case is x0rbin.
You will be able to use functions not defined in the main.c but using an extern reference to functions defined in the object files (*.o).
You can also link with .obj or other extensions if the object files have the correct format (such as COFF).
I am currently writing a short test app.
The compilation gives me these errors :
CC main.c
Building ../bin/pmono
./main.o:(.data+0x18): undefined reference to `busy'
./main.o:(.data+0x58): undefined reference to `busy'
./main.o:(.data+0x98): undefined reference to `busy'
./main.o:(.data+0xd8): undefined reference to `busy'
./main.o:(.data+0x118): undefined reference to `busy'
./main.o:(.data+0x158): more undefined references to `busy' follow
collect2: ld a retourné 1 code d'état d'exécution
I will try to narrow the code down to the specific parts.
Here is a structure I use which contain the desired reference :
/*
* Chained list of blocks from a frame of the cyclic executive
*/
typedef struct block {
long c; /* Worst case execution time */
long d; /* Deadline */
long p; /* Period */
void (*action) (long); /* Action performed by this frame */
struct block * next;
} *Frame;
The function pointer is placeholder for a generic function not written yet, declared as such in the same .h file :
/*
* Load the CPU for a determined time expressed in nanosecond
*/
void busy(long t);
The function is currently hollow in the c file :
void busy(long t) {
}
Finally, here is a sample default structure I use in my tests :
struct block D = {8,20,20,busy,0};
struct block C = {2,20,20,busy,&D};
struct block B = {3,10,10,busy,&C};
struct block A = {1,10,10,busy,&B};
Frame sequence0 = &A;
All of these parts are contained in a common source file shared between numerous implementations of periodic tasks. The compilation of the object file seems fine.
When I try to compile a given implementation, I first include the .h file, compile the .o file, then try to link the whole thing, using makefile. Here is one makefile to give you an idea :
BIN = ../bin/pmono
CC = gcc
SUBDIR = .
SRC = $(foreach dir, $(SUBDIR), $(wildcard $(dir)/*.c))
OBJ = $(SRC:.c=.o) $(wildcard ../common/*.o)
INCLUDES =
WARNINGS =
OPTIMISATION =
DEBUG =
XENO_CONFIG = /usr/xenomai/bin/xeno-config
XENO_POSIX_CFLAGS = $(shell $(XENO_CONFIG) --skin=posix --cflags)
XENO_POSIX_LDFLAGS = $(shell $(XENO_CONFIG) --skin=posix --ldflags)
CFLAGS = $(INCLUDES) $(XENO_POSIX_CFLAGS) $(WARNINGS) $(OPTIMISATION)
LDFLAGS = -lm $(XENO_POSIX_LDFLAGS) $(DEBUG)
all:.depend $(BIN)
%.o:%.c
#echo "CC $<"
#$(CC) -c $(CFLAGS) $< -o $#
$(BIN): $(OBJ)
#echo "Building ${BIN}"
#$(CC) $(OBJ) -o $# $(LDFLAGS)
clean:
rm -f $(OBJ)
distclean: clean
rm -f $(BIN)
rm -f ./.depend
.depend: $(SRC)
#echo "Génération des dépendances"
#$(CC) $(CFLAGS) -MM $(SRC) > .depend
-include .depend
So, I'm a beginner in this, and this is my understanding : the symbol of the busy function is missing in the main.o, while it exists in the cyclic_executive.o file. I don't understand how this is possible, as I include the cyclic_executive.h file, thus giving the proper declaration and prototype.
I think I'm doing it wrong, but I'm short on idea.
Also, I really dislike how I declare my "default" sequence. I know there is a proper way to do it, but I can't recall it... Does someone has a name to help search for it ?
Thanks.
You are not linking the file with the busy() function call.
Try this from the command line:
gcc main.c cyclic_executive.c
If it works, or at least doesn't give errors on the busy() function, that will confirm the issue. Then try
make all
This should print all the commands as they are executed. If you are still in the dark, try
make -d
That will give you a ton of diagnostics about what make is actually doing.