XC8 building a library, avoid double inclusion and definitions - Page 1
Forum section: electronics / beginners

author: TrickyNekro
author_rank: Frequent Contributor
timestamp: March 06, 2018, 12:18:06 pm
content: Hello ladies and gents,So I´m a bit a noobie to writing libraries and I have a rather simple question.I am using XC8 with MPLAB X.I am building a simple library and I want to avoid double inclusions.In my main I define my microcontroller, some libraries I want to use, like stdio.h, xc.h etc..I call the header of my library after all the other premade libraries, like:#include <stdio.h>#include <stdbool.h>etc...#include "../Mylib"Most of the premade libraries I call also in Mylib.If I don´t call them it pops up with an error as the compiler can not find the components I am using.Should I just include those libraries, as most probably have guards inside them or should I go like this:#ifndef STDIO_H#include <stdio.h>#endif etc...?Same happens with the XTAL_FREQ as I am forced to use delay in Mylib.I do define it in the main but the compiler gives me an error if I don´t write the below:#ifndef _XTAL_FREQ#define _XTAL_FREQ yogurt#endifSeems to be keeping the definition of the frequency from the main, but shouldn´t the compiler know it already?As I am defining the XTAL_FREQ before including Mylib!?Thanks for your time,Lefteris

author: Yansi
author_rank: Super Contributor
timestamp: March 06, 2018, 02:32:15 pm
content: Header file like this:#ifndef __YOURLIBRARY_H#define __YOURLIBRARY_H/* ALL Your library guts, including macros, etc. */#endif

author: TrickyNekro
author_rank: Frequent Contributor
timestamp: March 06, 2018, 03:00:59 pm
content: Yeah, I know that already, doesn´t help me much.My biggest problem right now is with the _XTAL_FREQ._delay_ms(x) and _delay_us(x) are used by my library, but the _XTAL_FREQ should be defined in the main.These are macros not functions from the xc.h library.The problem is that I need to define the _XTAL_FREQ in my library for the compiler not to give an error.But how does it come that the xc.h library can use the main.c definition of the _XTAL_FREQ and my library not?I´m getting a bit confused here.

author: newbrain
author_rank: Super Contributor
timestamp: March 06, 2018, 03:16:24 pm
content: Disclaimer: I don't do PICs, so the following is based on C standards and a little good will.Quote from: TrickyNekro on March 06, 2018, 12:18:06 pmFrom theC99 (draft) standard, chapter 7.12, clause 4:QuoteSo, don't worry about multiple inclusions of standard headers.It is good practice to protect you own include files from multiple inclusion, as Yansi correctly suggests.You might also sometimes findCode:#pragma onceThat has the same effect as the #ifndef guard.Though supported by most (all?) compilers, it's not part of the standard (implementation defined behaviour), so better avoided in your own code.Your problem with _XTAL_FREQ is not very clear to me.If you have code such as:Code:#define _XTAL_FREQ 8000000#include "xc.h"#include "../MyLib.h"the symbol will be defined for both included file.The delay routines are (AFAIK) actually macro in xc.h, so no problems in main.cOf course, if you use the delay macros in your source file (say, MyLib.c), _XTAL_FREQ must be somehow provided.

author: Ian.M
author_rank: Super Contributor
timestamp: March 06, 2018, 05:10:15 pm
content: There's a considerable difference between a source library and a static (precompiled) library. (Dynamic libraries aren't applicable to embedded MCUs smaller than a full SoC so lets leave their complexities aside.)XC8 muddies the waters slightly compared to a traditional C compiler because it compiles first to p-code, then to assembler, before finally linking. Most of its bundled libraries are static, supplied as p-code, and are effectively 'linked' with the p-code resulting from each C source file to form one monolithic assembler file that can be globally optimised. This contrasts to the traditional compilation process where object libraries, plus an object file for each .c source file are linked with no further optimisation.If you are working with static libraries of any sort, the library is pre-built, and the C preprocessor was run on it when it was built, so attempting to modify its behaviour using preprocessor symbols will fail. To actually modify its behaviour without rebuilding it it must have been built with hooks to allow the user to supply either callback functions that perform the action to be modified, or extern C constants (or variables) that will be used for default settings etc. e.g. see the XC8 putch() function that the user must supply for the printf() library function to work.A static library will have an associated header file, but that only declares the variables, C constants and interface of each function in the library. It should *NOT* define any function constant or variable.It is bad practice to try to pack a non-trivial source library into a single header file as you will almost always end up with multiple definitions as soon as your project grows to need multiple .c files. There is no way of automatically distinguishing the main .c file of a project, so there is no clean way of preventing a library implemented as a singe header from creating extra definitions for each additional .c file that uses it, other than to not write such a broken library with definitions in its header in the first place, or bodging it by manually #defining a flag before you #include it in the main .c file and carefully avoiding shooting yourself in the foot by copy/pasting that flag into other .c files!To understand how to structure a C project to avoid these issues, I recommend readingOrganizing Code Files in C and C++ @gamedev.net. Ignore the C++ stuff and don't bother with the updated version - its too PC centric.You cannot meaningfully use the XC8 __delay_ms() and __delay_us() macros in a static library, because the build-time value of _XTAL_FREQ is extremely unlikely to match your actual oscillator frequency. You therefore have to write your library as a source library, that will be added to each project that uses it as a collection of .c and .h files (which may reside in separate folder to the project if they are used by multiple projects) so that the full normal compilation sequence is followed for each file including preprocessing. If you need to define a global preprocessor symbol you've got two choices:* use the compiler command line-Dsymbol=valueto #define symbol in all .c files. There's a field for defining such simbols in the MPLAB XC8 toolsuite project options.* create a project wide file for shared symbols then include in in *ALL* .c files e.g.#include "hardware.h"N.B. you must use "" not <> as the preprocessor must be allowed to look in the current (working) directory to pull in the hardware.h that applies to the current project.

author: TrickyNekro
author_rank: Frequent Contributor
timestamp: March 07, 2018, 02:46:17 pm
content: I finally got it working but yeah I´ve learned what Ian said the hard way.You can not just build a static library and expect it to work. You have to include separately the .h and .c files and can not include libraries if you want the preprocessor macros to work.So I ended up just adding the _XTAL_FREQ=64000000 (my example) as a preprocessor macro and the .h and .c files separately as header and sources files for it to work.Adding it as a (static?) library even with the macro it refused to work. Still needed to define the _XTAL_FREQ in the library which is plain wrong (you don´t want to surprise the user :-P )I got an understanding of how I should work in the future with these stuff, so yeah thanks for the help!Cheers,Lefteris