How do you use CMSIS without an IDE? - arm

I am working with STM32F103C8T6 and would like to use CMSIS, which is essentially just register definitions and no code, to make my life easier while still staying at a low level. The problem is that I have no idea how to install the library for use on the command line with Makefile. All documentation seems to be bound with a vendor-specific IDE like STM32CubeIDE.
I suppose the first thing to do is to download the CMSIS library, which I found on GitHub. However, after unzipping ARM.CMSIS.5.6.0.pack I found no files named stm32f10x.h. I spend some more time and found a CMSIS pack for the specific MCU I'm using, but it doesn't contain core_cm3.h, which however presents in ARM.CMSIS.5.6.0.pack. The document says I need to include both to my project, so do I need to copy the files downloaded from different places to my project, or what?
As a bonus question: what is the relationship between CMSIS and Keli? The device-specific CMSIS pack is downloaded from www.keil.com, but I don't want to use Keil MDK for now, as it appears to be a commercial product, and the GNU Arm toolchain is serving me pretty well.
Edit: I should have been more specific from the beginning, but now let's focus on how to build the Basic CMSIS Example as a minimal, complete and verifiable example.
What I have done:
Download and unzip CMSIS-Core and CMSIS-DFP to /Users/nalzok/Developer/CMSIS/ARM.CMSIS.5.6.0/ and /Users/nalzok/Developer/CMSIS/Packs/Keil.STM32F1xx_DFP.2.3.0/, respectively.
Create a file named main.c, and copy the content of the basic example to it.
Add #define STM32F10X_MD on the very first line to specify the chip.
Fix typos: replace the : on line 31 to ;, and replace line 33 to timer1_init (42);.
Build and get an error
/tmp $ arm-none-eabi-gcc -I/Users/nalzok/Developer/CMSIS/ARM.CMSIS.5.6.0/CMSIS/Include/ -I/Users/nalzok/Developer/CMSIS/Packs/Keil.STM32F1xx_DFP.2.3.0/Device/Include/ main.c
main.c: In function 'main':
main.c:42:5: warning: implicit declaration of function 'Get_InputValues' [-Wimplicit-function-declaration]
42 | Get_InputValues (); // Read Values
| ^~~~~~~~~~~~~~~
main.c:44:5: warning: implicit declaration of function 'Calculation_Response' [-Wimplicit-function-declaration]
44 | Calculation_Response (); // Calculate Results
| ^~~~~~~~~~~~~~~~~~~~
main.c:45:5: warning: implicit declaration of function 'Output_Response' [-Wimplicit-function-declaration]
45 | Output_Response (); // Output Results
| ^~~~~~~~~~~~~~~
/var/folders/m4/7my6q_kj6pxgzb1b7pxyhp0h0000gn/T//cc1ZVBaH.s: Assembler messages:
/var/folders/m4/7my6q_kj6pxgzb1b7pxyhp0h0000gn/T//cc1ZVBaH.s:197: Error: selected processor does not support `wfe' in ARM mode
/var/folders/m4/7my6q_kj6pxgzb1b7pxyhp0h0000gn/T//cc1ZVBaH.s:310: Error: selected processor does not support `cpsid i' in ARM mode
/var/folders/m4/7my6q_kj6pxgzb1b7pxyhp0h0000gn/T//cc1ZVBaH.s:318: Error: selected processor does not support `cpsie i' in ARM mode
As per #KamilCuk's comment below, I added more options and commented out the functions Get_InputValues, Calculation_Response, and Output_Response, but now I am having some different errors.
/tmp $ arm-none-eabi-gcc -I/Users/nalzok/Developer/CMSIS/ARM.CMSIS.5.6.0/CMSIS/Include/ -I/Users/nalzok/Developer/CMSIS/Packs/Keil.STM32F1xx_DFP.2.3.0/Device/Include/ -D STM32F1 -D STM32F103x6 -mthumb -mcpu=cortex-m3 main.c
/Users/nalzok/opt/xPacks/arm-none-eabi-gcc/9.2.1-1.1/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: /Users/nalzok/opt/xPacks/arm-none-eabi-gcc/9.2.1-1.1/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libc.a(lib_a-exit.o): in function `exit':
exit.c:(.text.exit+0x16): undefined reference to `_exit'
/Users/nalzok/opt/xPacks/arm-none-eabi-gcc/9.2.1-1.1/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: /var/folders/m4/7my6q_kj6pxgzb1b7pxyhp0h0000gn/T//ccqfC5LA.o: in function `Device_Initialization':
main.c:(.text+0x164): undefined reference to `SystemCoreClock'
collect2: error: ld returned 1 exit status

For the latest device headers, I suggest downloading STM32CubeF1 package from the ST website. Among other things (Middlewares, HAL etc.), this package contains the required device headers in /Drivers/CMSIS/Device folder. You need STM32F103xB symbol defined for stm32f1xx.h header to work correctly.
Of course, STM32CubeF1 package also contains CMSIS libraries but they are generally a little bit outdated. I prefer to download them as .pack files from the github repo you mentioned. You need the headers in /CMSIS/Core at least. You may add additional parts of the CMSIS if you wish. Some of them (like DSP) may also need you to add static libraries provided in /Lib folders.
Please be aware that if you clone the CMSIS repo from github instead of downloading the .pack file, you end up with placeholder versions of the static libraries, as the project uses git LFS. You can't use these static library files (.a files) directly as they are just some kind of pointers. I'm not familiar with git LFS, but I guess you need some git commands (maybe checkout) to tell your PC to download the actual .a files.
Also note that sometimes CMSIS folder structure changes from version to version. The folder structure you get in STM32CubeF1 may be different from the one you download from the official CMSIS repo.
I forgot to mention: Other than CMSIS and ST device headers, you also need the following files:
system_stm32f1xx.c (STM32CubeF1 package /Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates folder)
startup_stm32f103xb.s (STM32CubeF1 package /Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc folder)
A linker script from STM32CubeF1 package /Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc/linker folder. Strangely, there is none for STM32F103x8, so you probably need to pick STM32F103xB and modify it. I use an IDE generated one.
Update:
Here you can find a minimal project created in STM32CubeIDE. I created an empty C project. The IDE provides a linker script and a startup file (.s) but I deleted them and used the ones included in the STM32CubeF1 package. I also deleted unrelated header files from the /Drivers/Device/ST/STM32F1xx/Include directory. But I didn't touched the ones in the /Drivers/CMSIS/Core/Include although there are lots of unrelated files there, as it's harder to determine which ones are needed and which ones are not.
I know that you look for a solution without an IDE, but I think this example project can at least give you some clues about the required files and the project structure.
Note: The example project name is blinky.cube but there is no Cube in the project. I use this naming convention just to specify the IDE I use, which is STM32CubeIDE in this case.

For the part of CMSIS your are referring to, some is supplied by ARM (CMSIS core) and some is supplied by your chip vendor (Device Family Pack). As you have discovered, CMSIS software packs are just zip files by another name. You may unzip them wherever you wish. As you are aware, core CMSIS and most of the vendor specific part consists of just header files. It is then necessary to include the proper directories in the compiler include path, typically using -I... command line options.
One type of vendor software pack is called a Device Family Pack. In addition to vendor specific peripheral definitions, they usually contain start up code and often times linker scripts that match the layout of the SOC memory. These are worth finding and will save the work of vector table layout and other such low level code.
For the bonus: Keil is a maker of software tools and is owned by ARM. The nicer features of CMSIS software packs, like distributing and updating them over a network, are supported by the Keil IDE and Keil maintains a repository of common SOC packs. I also usually use the GNU compiler, but have used Keil and its built-in CMSIS awareness and software pack availablity to good effect. I have even built a few software packs for custom work. I suggest a continued reading of the CMSIS documentation paying some attention to the section on packs. You don't have to have an IDE that manages the packs for you. Since they are simply zip files, you undertake that task yourself.

Related

SDL2 errors on Visual studio Code while setting it up [duplicate]

I want to make a game using SDL2, but I'm unable to compile and/or run my code, please help!
SDL2 is notoriously hard to set up, and it's often the first library aspiring game developers try to use.
This post is intended as a canonical duplicate for common problems with setting up SDL2.
This answer is about MinGW / GCC, and not Visual Studio.
This answer only applies to Windows.
Common errors
The common errors are:
SDL.h: No such file or directory (when compiling)
Various SDL_main problems: "undefined reference to SDL_main", "conflicting types for SDL_main" or "number of arguments doesn't match prototype", etc. (when compiling or linking)
undefined reference to other functions (when linking)
DLL problems: (when running your program)
'??.dll' was not found
procedure entry point ... could not be located in ..., and other mysterious DLL-related errors
The program seemingly doing nothing when launched
This list is sorted from bad to good. If you change something and get a different error, use this list to tell if you made things better or worse.
The preamble
0. Don't follow bad advice.
Some resources will suggest you to do #define SDL_MAIN_HANDLED or #undef main. Don't blindly follow that advice, it's not how SDL2 is intended to be used.
If you do everything correcty, it will never be necessary. Learn the intended approach first. Then you can research what exactly that does, and make an educated decision.
1. Figure out how to compile directly from the console, you can start using an IDE and/or build system later.
If you're using an IDE, I suggest to first make sure you're able to compile your program directly from the console, to rule out any IDE configuration problems. After you figure that out, you can use the same compiler options in your IDE.
The same applies to build systems, such as CMake.
2. Download the right SDL2 files. Make sure you have the right files. You need the archive called SDL2-devel-2.0.x-mingw.tar.gz from here.
Extract it to any directory, preferably somewhere near your source code. Extracting into the compiler installation directory is often considered a bad practice (and so is copying them to C:\Windows, which is a horrible idea).
3. Know the difference between compiler flags and linker flags. A "flag" is an option you specify in the command line when building your program. When you use a single command, e.g. g++ foo.cpp -o foo.exe, all your flags are added to the same place (to this single command).
But when you build your program in two steps, e.g.:
g++ foo.cpp -c -o foo.o (compiling)
g++ foo.o -o foo.exe (linking)
you have to know which of the two commands to add a flag to. Those are "compiler flags" and "linker flags" respectively.
Most IDEs will require you to specify compiler and linker flags separately, so even if you use a single command now, it's good to know which flag goes where.
Unless specified otherwise, the order of the flags doesn't matter.
SDL.h: No such file or directory
Or any similar error related to including SDL.h or SDL2/SDL.h.
You need to tell your compiler where to look for SDL.h. It's in the SDL files you've downloaded (see preamble).
Add -Ipath to your compiler flags, where path is the directory where SDL.h is located.
Example: -IC:/Users/HolyBlackCat/Downloads/SDL2-2.0.12/x86_64-w64-mingw32/include/SDL2. Relative paths work too, e.g. -ISDL2-2.0.12/x86_64-w64-mingw32/include/SDL2.
Note that the path will be different depending on how you write the #include:
If you do #include <SDL.h>, then the path should end with .../include/SDL2 (like above). This is the recommended way.
If you do #include <SDL2/SDL.h>, then the path should end with .../include.
Various SDL_main problems
You can get several different errors mentioning SDL_main, such as undefined reference to SDL_main, or conflicting types for 'SDL_main', or number of arguments doesn't match prototype, etc.
You need to have a main function. Your main function must look like int main(int, char **). NOT int main() and NOT void main(). This is a quirk of SDL2, related to it doing #define main SDL_main.
Adding parameter names is allowed (and is mandatory in C), e.g. int main(int argc, char **argv). Also the second parameter can be written as char *[] or with a name: char *argv[]. No other changes are allowed.
If your project has multiple source files, make sure to include SDL.h in the file that defines the main function, even if it doesn't otherwise use SDL directly.
Try to avoid #define SDL_MAIN_HANDLED or #undef main when solving this issue, see preamble for explanation.
undefined reference to various functions
• undefined reference to SDL_...
The error message will mention various SDL_... functions, and/or WinMain. If it mentions SDL_main, consult the section "Various SDL_main problems" above. If the function names don't start with SDL_, consult the section "undefined reference to other functions" below.
You need to add following linker flags: -lmingw32 -lSDL2main -lSDL2 -Lpath, where path is the directory where libSDL2.dll.a and libSDL2main.a (which you've downloaded) are located. The order of the -l... flags matters. They must appear AFTER any .c/.cpp/.o files.
Example: -LC:/Users/HolyBlackCat/Desktop/SDL2-2.0.12/x86_64-w64-mingw32/lib. Relative paths work too, e.g. -LSDL2-2.0.12/x86_64-w64-mingw32/lib.
When you use -l???, the linker will look for a file called lib???.dll.a or lib???.a (and some other variants), which is why we need to pass the location of those files. libmingw32.a (corresponding to -lmingw32) is shipped with your compiler, so it already knows where to find it.
I added all those flags and nothing changed, or I'm getting skipping incompatible X when searching for Y:
You probably use the wrong SDL .a files. The archive you downloaded contains two sets of files: i686-w64-mingw32 (32-bit) and x86_64-w64-mingw32 (64-bit). You must use the files matching your compiler, which can also be either 32-bit or 64-bit.
Print (8*sizeof(void*)) to see if your compiler is 32-bit or 64-bit.
Even if you think you use the right files, try the other ones to be sure.
Some MinGW versions can be switched between 32-bit and 64-bit modes using -m32 and -m64 flags (add them to both compiler and linker flags).
I get undefined reference to a specific function:
• undefined reference to WinMain only
There are several possibilities, all of which were covered in the previous section:
You forgot -lmingw32 and/or -lSDL2main linker flags.
You must use following linker flags, in this exact order, after
any .c/.cpp/.o files: -lmingw32 -lSDL2main -lSDL2
The libSDL2main.a file you use doesn't match your compiler (32-bit file with a 64-bit compiler, or vice versa).
Try to avoid #define SDL_MAIN_HANDLED or #undef main when solving this issue, see preamble for explanation.
• undefined reference to SDL_main only
See the section "Various SDL_main problems" above.
• undefined reference to other functions
Your linker found and used libSDL2.a, but it should be finding and using libSDL2.dll.a. When both are available, it prefers the latter by default, meaning you didn't copy the latter to the directory you passed to -L.
If you intended to perform static linking, see the section called "How do I distribute my app to others?" below.
Nothing happens when I try run my app
Let's say you try to run your app, and nothing happens. Even if you try to print something at the beginning of main(), it's not printed.
Windows has a nasty habit of not showing some DLL-related errors when the program is started from the console.
If you were running your app from the console (or from an IDE), instead try double-clicking the EXE in the explorer. Most probably you'll now see some DLL-related error; then consult one of the next sections.
??.dll was not found
Copy the .dll mentioned in the error message, and place it next to your .exe.
If the DLL is called SDL2.dll, then it's in the SDL files you've downloaded (see preamble). Be aware that there are two different SDL2.dlls: a 32-bit one (in the i686-w64-mingw32 directory), and a 64-bit one (in x86_64-w64-mingw32). Get the right one, if necessary try both.
Any other DLLs will be in your compiler's bin directory (the directory where gcc.exe is located).
You might need to repeat this process 3-4 times, this is normal.
For an automatic way of determining the needed DLLs, see the next section.
procedure entry point ... could not be located in ... and other cryptic DLL errors
Your program needs several .dlls to run, and it found a wrong version of one, left over from some other program you have installed.
It looks for DLLs in several different places, but the directory with the .exe has the most priority.
You should copy all DLLs your program uses (except the system ones) into the directory where your .exe is located.
A reliable way to get a list of needed DLLs is to blindly copy a bunch of DLLs, and then remove the ones that turn out to be unnecessary:
Copy SDL2.dll. It's in the SDL files you've downloaded (see preamble). Be aware that there are two different SDL2.dlls: a 32-bit one (in the i686-w64-mingw32 directory), and a 64-bit one (in x86_64-w64-mingw32). Get the right one, if necessary try both.
Copy all DLLs from your compiler's bin directory (the directory where gcc.exe is located).
Now your program should run, but we're not done yet.
Download NTLDD (or some other program that displays a list of used DLLs). Run ntldd -R your_program.exe.
Any DLL not mentioned in its output should be removed from the current directory. Your program uses everything that remains.
I ended up with following DLLs, expect something similar: SDL2.dll, libgcc_s_seh-1.dll, libstdc++-6.dll (C++ only), libwinpthread-1.dll.
Can I determine the needed DLLs without copying excessive ones?
Yes, but it's less reliable.
Your program searches for DLLs in following locations, in this order:
The directory where your .exe is located.
C:\Windows, including some of its subdirectories.
The directories listed in PATH.
Assuming you (or some jank installer) didn't put any custom DLLs into C:\Windows, adding your compiler's bin directory to the PATH (preferably as the first entry) and either putting SDL2.dll in the same directory as the .exe or into some directory in the PATH should be enough for your program to work.
If this works, you can then run ntldd without copying any DLLs beforehand, and copy only the necessary ones. The reason why you'd want to copy them at all at this point (since your app already works) is to be able to distribute it to others, without them having to install the compiler for its DLLs. Skip any DLLs located outside of your compiler's bin directory (except for SDL2.dll).
Note that the possibility of having weird DLLs in C:\Windows is real. E.g. Wine tends to put OpenAL32.dll into C:\Windows, so if you try this process with OpenAL on Wine, it will fail. If you're making a sciprt that runs ntldd automatically, prefer copying the DLLs (or at least symlinking them - I heard MSYS2 can emulate symlinks on Windows?).
Can I make an EXE that doesn't depend on any DLLs?
It's possible to make an .exe that doesn't depend on any (non-system) .dlls by using the -static linker flag, this is called "static linking". This is rarely done, and you shouldn't need to do this if you did the above steps correctly. This requires some additional linker flags; they are listed in file ??-w64-mingw32/lib/pkgconfig/sdl2.pc shipped with SDL, in the Libs.private section. Notice that there are two files, for x32 and x64 respectively.
How do I distribute my app to others?
Follow the steps in the previous section, titled procedure entry point ... could not be located in ....
A saner alternative?
There is MSYS2.
It has a package manager that lets you download prebuilt libraries, and, as a bonus, a fresh version of the compiler.
Install SDL2 from its package manager. Use a tool called pkg-config (also from the package manager) to automatically determine all necessary flags (pkg-config --cflags SDL2 for compiler flags, pkg-config --libs SDL2 for linker flags).
This is the same experience as you would have on Linux (maybe except for some DLL management hassle).
Bonus - Other problems
Q: My program always opens a console window when I run it, how do I hide it?
A: Add -mwindows to the linker flags.
Q: I get error 'SDL_VideoMode' wasn't declared in this scope.
A: SDL_VideoMode is from SDL1.2, it's not a part of the newer SDL2. Your code was written for the outdated version of SDL. Find a better tutorial that deals specifically with SDL2.
Q: My program has the default file icon, but I want a custom one.
A: Your icon must be in the .ico format. If your graphics editor doesn't support it, make a series of .pngs of common sizes (e.g. 16x16, 32x32, 48x48, 64x64), then convert them to a single .ico using ImageMagick: magick *.png result.ico (or with convert instead of magick).
Create a file with the .rc extension (say, icon.rc), with following contents MyIconName ICON "icon.ico" (where MyIconName is an arbitrary name, and "icon.ico" is the path to the icon). Convert the file to an .o using windres -O res -i icon.rc -o icon.o (the windres program is shipped with your compiler). Specify the resulting .o file when linking, e.g. g++ foo.cpp icon.o -o foo.exe.
Recent versions of SDL2 have a nice property of using the same icon as the window icon, so you don't have to use SDL_SetWindowIcon.
A solution for Visual Studio:
Why not use a package manager? I use vcpkg, and it makes super easy to consume 3rd party libraries. Grab the vcpkg source, and extract it to a safe place, like C:/, then run its bootstrap script bootstrap-vcpkg.bat, this will generate vcpkg executable. Then run vcpkg integrate install to make libraries installed with vcpkg available in Visual Studio.
Search for the library you need:
vcpkg search sdl
imgui[sdl2-binding] Make available SDL2 binding
libwebp[vwebp-sdl] Build the vwebp viewer tool.
magnum[sdl2application] Sdl2Application library
sdl1 1.2.15#12 Simple DirectMedia Layer is a cross-platform development library designed to p...
sdl1-net 1.2.8-3 Networking library for SDL
sdl2 2.0.12-1 Simple DirectMedia Layer is a cross-platform
...
Install it with: vcpkg install sdl2.
Now you just need include SDL2 headers, and everything will work out of the box. The library will be linked automatically.
You can learn more about vcpkg here.
On Mac this is what I follow for XCode (must install g++):
sdl linking:
g++ main.cpp -o main $(sdl2-config --cflags --libs)
XCODE project steps:
open terminal app (macOS)
BUILD SETTINGS (select 'all' and 'combined' search bar enter: "search")
click on "header search paths(way right side click)
add: /usr/local/include
BUILD PHASES --> LINK BINARY LIBRARIES (click plus)
type in SDL --> click "add other"
press: command+SHIFT+g (to bring search bar)
type in: usr/local/Cellar
navigate to: SDL2 -->2.0.8 -->lib --> libSDL2-2.2.0.dylib (make sure not shortcut)

How to successfully compile an SDL2 C program with MinGW [duplicate]

I want to make a game using SDL2, but I'm unable to compile and/or run my code, please help!
SDL2 is notoriously hard to set up, and it's often the first library aspiring game developers try to use.
This post is intended as a canonical duplicate for common problems with setting up SDL2.
This answer is about MinGW / GCC, and not Visual Studio.
This answer only applies to Windows.
Common errors
The common errors are:
SDL.h: No such file or directory (when compiling)
Various SDL_main problems: "undefined reference to SDL_main", "conflicting types for SDL_main" or "number of arguments doesn't match prototype", etc. (when compiling or linking)
undefined reference to other functions (when linking)
DLL problems: (when running your program)
'??.dll' was not found
procedure entry point ... could not be located in ..., and other mysterious DLL-related errors
The program seemingly doing nothing when launched
This list is sorted from bad to good. If you change something and get a different error, use this list to tell if you made things better or worse.
The preamble
0. Don't follow bad advice.
Some resources will suggest you to do #define SDL_MAIN_HANDLED or #undef main. Don't blindly follow that advice, it's not how SDL2 is intended to be used.
If you do everything correcty, it will never be necessary. Learn the intended approach first. Then you can research what exactly that does, and make an educated decision.
1. Figure out how to compile directly from the console, you can start using an IDE and/or build system later.
If you're using an IDE, I suggest to first make sure you're able to compile your program directly from the console, to rule out any IDE configuration problems. After you figure that out, you can use the same compiler options in your IDE.
The same applies to build systems, such as CMake.
2. Download the right SDL2 files. Make sure you have the right files. You need the archive called SDL2-devel-2.0.x-mingw.tar.gz from here.
Extract it to any directory, preferably somewhere near your source code. Extracting into the compiler installation directory is often considered a bad practice (and so is copying them to C:\Windows, which is a horrible idea).
3. Know the difference between compiler flags and linker flags. A "flag" is an option you specify in the command line when building your program. When you use a single command, e.g. g++ foo.cpp -o foo.exe, all your flags are added to the same place (to this single command).
But when you build your program in two steps, e.g.:
g++ foo.cpp -c -o foo.o (compiling)
g++ foo.o -o foo.exe (linking)
you have to know which of the two commands to add a flag to. Those are "compiler flags" and "linker flags" respectively.
Most IDEs will require you to specify compiler and linker flags separately, so even if you use a single command now, it's good to know which flag goes where.
Unless specified otherwise, the order of the flags doesn't matter.
SDL.h: No such file or directory
Or any similar error related to including SDL.h or SDL2/SDL.h.
You need to tell your compiler where to look for SDL.h. It's in the SDL files you've downloaded (see preamble).
Add -Ipath to your compiler flags, where path is the directory where SDL.h is located.
Example: -IC:/Users/HolyBlackCat/Downloads/SDL2-2.0.12/x86_64-w64-mingw32/include/SDL2. Relative paths work too, e.g. -ISDL2-2.0.12/x86_64-w64-mingw32/include/SDL2.
Note that the path will be different depending on how you write the #include:
If you do #include <SDL.h>, then the path should end with .../include/SDL2 (like above). This is the recommended way.
If you do #include <SDL2/SDL.h>, then the path should end with .../include.
Various SDL_main problems
You can get several different errors mentioning SDL_main, such as undefined reference to SDL_main, or conflicting types for 'SDL_main', or number of arguments doesn't match prototype, etc.
You need to have a main function. Your main function must look like int main(int, char **). NOT int main() and NOT void main(). This is a quirk of SDL2, related to it doing #define main SDL_main.
Adding parameter names is allowed (and is mandatory in C), e.g. int main(int argc, char **argv). Also the second parameter can be written as char *[] or with a name: char *argv[]. No other changes are allowed.
If your project has multiple source files, make sure to include SDL.h in the file that defines the main function, even if it doesn't otherwise use SDL directly.
Try to avoid #define SDL_MAIN_HANDLED or #undef main when solving this issue, see preamble for explanation.
undefined reference to various functions
• undefined reference to SDL_...
The error message will mention various SDL_... functions, and/or WinMain. If it mentions SDL_main, consult the section "Various SDL_main problems" above. If the function names don't start with SDL_, consult the section "undefined reference to other functions" below.
You need to add following linker flags: -lmingw32 -lSDL2main -lSDL2 -Lpath, where path is the directory where libSDL2.dll.a and libSDL2main.a (which you've downloaded) are located. The order of the -l... flags matters. They must appear AFTER any .c/.cpp/.o files.
Example: -LC:/Users/HolyBlackCat/Desktop/SDL2-2.0.12/x86_64-w64-mingw32/lib. Relative paths work too, e.g. -LSDL2-2.0.12/x86_64-w64-mingw32/lib.
When you use -l???, the linker will look for a file called lib???.dll.a or lib???.a (and some other variants), which is why we need to pass the location of those files. libmingw32.a (corresponding to -lmingw32) is shipped with your compiler, so it already knows where to find it.
I added all those flags and nothing changed, or I'm getting skipping incompatible X when searching for Y:
You probably use the wrong SDL .a files. The archive you downloaded contains two sets of files: i686-w64-mingw32 (32-bit) and x86_64-w64-mingw32 (64-bit). You must use the files matching your compiler, which can also be either 32-bit or 64-bit.
Print (8*sizeof(void*)) to see if your compiler is 32-bit or 64-bit.
Even if you think you use the right files, try the other ones to be sure.
Some MinGW versions can be switched between 32-bit and 64-bit modes using -m32 and -m64 flags (add them to both compiler and linker flags).
I get undefined reference to a specific function:
• undefined reference to WinMain only
There are several possibilities, all of which were covered in the previous section:
You forgot -lmingw32 and/or -lSDL2main linker flags.
You must use following linker flags, in this exact order, after
any .c/.cpp/.o files: -lmingw32 -lSDL2main -lSDL2
The libSDL2main.a file you use doesn't match your compiler (32-bit file with a 64-bit compiler, or vice versa).
Try to avoid #define SDL_MAIN_HANDLED or #undef main when solving this issue, see preamble for explanation.
• undefined reference to SDL_main only
See the section "Various SDL_main problems" above.
• undefined reference to other functions
Your linker found and used libSDL2.a, but it should be finding and using libSDL2.dll.a. When both are available, it prefers the latter by default, meaning you didn't copy the latter to the directory you passed to -L.
If you intended to perform static linking, see the section called "How do I distribute my app to others?" below.
Nothing happens when I try run my app
Let's say you try to run your app, and nothing happens. Even if you try to print something at the beginning of main(), it's not printed.
Windows has a nasty habit of not showing some DLL-related errors when the program is started from the console.
If you were running your app from the console (or from an IDE), instead try double-clicking the EXE in the explorer. Most probably you'll now see some DLL-related error; then consult one of the next sections.
??.dll was not found
Copy the .dll mentioned in the error message, and place it next to your .exe.
If the DLL is called SDL2.dll, then it's in the SDL files you've downloaded (see preamble). Be aware that there are two different SDL2.dlls: a 32-bit one (in the i686-w64-mingw32 directory), and a 64-bit one (in x86_64-w64-mingw32). Get the right one, if necessary try both.
Any other DLLs will be in your compiler's bin directory (the directory where gcc.exe is located).
You might need to repeat this process 3-4 times, this is normal.
For an automatic way of determining the needed DLLs, see the next section.
procedure entry point ... could not be located in ... and other cryptic DLL errors
Your program needs several .dlls to run, and it found a wrong version of one, left over from some other program you have installed.
It looks for DLLs in several different places, but the directory with the .exe has the most priority.
You should copy all DLLs your program uses (except the system ones) into the directory where your .exe is located.
A reliable way to get a list of needed DLLs is to blindly copy a bunch of DLLs, and then remove the ones that turn out to be unnecessary:
Copy SDL2.dll. It's in the SDL files you've downloaded (see preamble). Be aware that there are two different SDL2.dlls: a 32-bit one (in the i686-w64-mingw32 directory), and a 64-bit one (in x86_64-w64-mingw32). Get the right one, if necessary try both.
Copy all DLLs from your compiler's bin directory (the directory where gcc.exe is located).
Now your program should run, but we're not done yet.
Download NTLDD (or some other program that displays a list of used DLLs). Run ntldd -R your_program.exe.
Any DLL not mentioned in its output should be removed from the current directory. Your program uses everything that remains.
I ended up with following DLLs, expect something similar: SDL2.dll, libgcc_s_seh-1.dll, libstdc++-6.dll (C++ only), libwinpthread-1.dll.
Can I determine the needed DLLs without copying excessive ones?
Yes, but it's less reliable.
Your program searches for DLLs in following locations, in this order:
The directory where your .exe is located.
C:\Windows, including some of its subdirectories.
The directories listed in PATH.
Assuming you (or some jank installer) didn't put any custom DLLs into C:\Windows, adding your compiler's bin directory to the PATH (preferably as the first entry) and either putting SDL2.dll in the same directory as the .exe or into some directory in the PATH should be enough for your program to work.
If this works, you can then run ntldd without copying any DLLs beforehand, and copy only the necessary ones. The reason why you'd want to copy them at all at this point (since your app already works) is to be able to distribute it to others, without them having to install the compiler for its DLLs. Skip any DLLs located outside of your compiler's bin directory (except for SDL2.dll).
Note that the possibility of having weird DLLs in C:\Windows is real. E.g. Wine tends to put OpenAL32.dll into C:\Windows, so if you try this process with OpenAL on Wine, it will fail. If you're making a sciprt that runs ntldd automatically, prefer copying the DLLs (or at least symlinking them - I heard MSYS2 can emulate symlinks on Windows?).
Can I make an EXE that doesn't depend on any DLLs?
It's possible to make an .exe that doesn't depend on any (non-system) .dlls by using the -static linker flag, this is called "static linking". This is rarely done, and you shouldn't need to do this if you did the above steps correctly. This requires some additional linker flags; they are listed in file ??-w64-mingw32/lib/pkgconfig/sdl2.pc shipped with SDL, in the Libs.private section. Notice that there are two files, for x32 and x64 respectively.
How do I distribute my app to others?
Follow the steps in the previous section, titled procedure entry point ... could not be located in ....
A saner alternative?
There is MSYS2.
It has a package manager that lets you download prebuilt libraries, and, as a bonus, a fresh version of the compiler.
Install SDL2 from its package manager. Use a tool called pkg-config (also from the package manager) to automatically determine all necessary flags (pkg-config --cflags SDL2 for compiler flags, pkg-config --libs SDL2 for linker flags).
This is the same experience as you would have on Linux (maybe except for some DLL management hassle).
Bonus - Other problems
Q: My program always opens a console window when I run it, how do I hide it?
A: Add -mwindows to the linker flags.
Q: I get error 'SDL_VideoMode' wasn't declared in this scope.
A: SDL_VideoMode is from SDL1.2, it's not a part of the newer SDL2. Your code was written for the outdated version of SDL. Find a better tutorial that deals specifically with SDL2.
Q: My program has the default file icon, but I want a custom one.
A: Your icon must be in the .ico format. If your graphics editor doesn't support it, make a series of .pngs of common sizes (e.g. 16x16, 32x32, 48x48, 64x64), then convert them to a single .ico using ImageMagick: magick *.png result.ico (or with convert instead of magick).
Create a file with the .rc extension (say, icon.rc), with following contents MyIconName ICON "icon.ico" (where MyIconName is an arbitrary name, and "icon.ico" is the path to the icon). Convert the file to an .o using windres -O res -i icon.rc -o icon.o (the windres program is shipped with your compiler). Specify the resulting .o file when linking, e.g. g++ foo.cpp icon.o -o foo.exe.
Recent versions of SDL2 have a nice property of using the same icon as the window icon, so you don't have to use SDL_SetWindowIcon.
A solution for Visual Studio:
Why not use a package manager? I use vcpkg, and it makes super easy to consume 3rd party libraries. Grab the vcpkg source, and extract it to a safe place, like C:/, then run its bootstrap script bootstrap-vcpkg.bat, this will generate vcpkg executable. Then run vcpkg integrate install to make libraries installed with vcpkg available in Visual Studio.
Search for the library you need:
vcpkg search sdl
imgui[sdl2-binding] Make available SDL2 binding
libwebp[vwebp-sdl] Build the vwebp viewer tool.
magnum[sdl2application] Sdl2Application library
sdl1 1.2.15#12 Simple DirectMedia Layer is a cross-platform development library designed to p...
sdl1-net 1.2.8-3 Networking library for SDL
sdl2 2.0.12-1 Simple DirectMedia Layer is a cross-platform
...
Install it with: vcpkg install sdl2.
Now you just need include SDL2 headers, and everything will work out of the box. The library will be linked automatically.
You can learn more about vcpkg here.
On Mac this is what I follow for XCode (must install g++):
sdl linking:
g++ main.cpp -o main $(sdl2-config --cflags --libs)
XCODE project steps:
open terminal app (macOS)
BUILD SETTINGS (select 'all' and 'combined' search bar enter: "search")
click on "header search paths(way right side click)
add: /usr/local/include
BUILD PHASES --> LINK BINARY LIBRARIES (click plus)
type in SDL --> click "add other"
press: command+SHIFT+g (to bring search bar)
type in: usr/local/Cellar
navigate to: SDL2 -->2.0.8 -->lib --> libSDL2-2.2.0.dylib (make sure not shortcut)

Having Difficulty Integrating JSON Library with My AVR Microcontroller Code

I am a relatively inexperienced C developer with no previous experience in integrating libraries made by other developers into existing projects.
Basically, I need a means of parsing JSON data in an AVR microcontroller for a university project. To this end I attempted to download and integrate jansson (https://github.com/akheron/jansson) into my existing build of the microcontroller code. I am working with Atmel Studio in Windows 10, but I have also installed Code::Blocks with MinGW GCC (on the same Windows 10 installation) for the purpose of building the library, and to attempt to integrate the library into a native Windows application. So far, neither has been successful, and I get the same errors. All of the online resources I've found so far have been to basic to be useful, or well beyond my comprehension.
This is what I have done thus far:
I began by attempting to build the software and then integrate it into an existing project per the instructions in https://jansson.readthedocs.io/en/2.11/gettingstarted.html. I installed CMake, built the project files for Code::Blocks with cmake.exe -G “CodeBlocks - MinGW Makefiles”, then opened the project and built everything. A few of the targets (I believe related to testing) failed to build, but jansson itself built and output libjansson.a to the \lib\ directory, so I didn’t think too much of it.
That is as far as I’ve been able to get. In both Atmel Studio and Code::Blocks, I do the same thing: add jansson.h to the relevant include paths, add #include “jansson.h” to all of the relevant files, and add libjansson.a as a library in each IDE’s respective linker options. I’ve tried various things like adding and removing flags to the linker, but the output is always “cannot find -ljansson”, “undefined reference to ‘json_object_seed’” (which is a function in the API I’m calling for no reason other than to see if the project has built properly) and/or “ld returned 1 exit status”.
I cannot help but feel as if the issue is with the line “cc -o prog prog.c -ljansson” in the documentation linked above. I really just don’t understand how to set up the linker properly to get the project to build.
If anyone could give some insight into what I’m doing wrong/the correct way to link this library I would appreciate it a lot.
The library itself should be built with appropriate toolchain. I assume that you built your library twice, one version using MinGW toolchain and other with avr-gcc toolchain.
If you compile target application and linker cannot find library, then try to add path of directory that contains *.a file of library to linker settings (linker search path). Let's say you have: /path/to/lib/libjansson.a
In Code::Blocks: Project → Build options → Search directories → Linker add /path/to/lib/. Then it should link with include path set, for example: cc -o prog prog.c -ljansson -L/path/to/lib/
In Atmel Studio when you add a library in Solution Explorer → Libraries → Add Library it should automatically add library search path to linker options. If you check Project → Properties → AVR/GNU Linker there should be (between other options): -Wl,-ljansson -Wl,-L"/path/to/lib/"
If you copied library files (libjansson.a and jansson.h) to your application's project directory, it will be convenient to use relative paths to library files.

gtk.h missing in Visual Studio for Linux Development

I'm currently trying to write an app for Raspberry Pi 3B under Rasbpian with aid of Linux Development plugin in Visual Studio 2017 Community. I managed to successfully deploy 'Blink' example, nobly attached by Microsoft folks, according to tutorial, and that went well. I even made some transmission over SPI thanks to wiringPi library. Then I would like to add some GUI to my app, so that one could, for example, make some transmission on click of a button on screen.
IntelliSense hinted me, that, in fact, there is gtk-3.0 library present in toolset. It seems that libraries are being copied from target device on every connection or so and I installed gtk on my Raspberry. So I added a simple line to this Blink example:
#include <gtk-3.0/gtk/gtk.h>
On compilation attempt, of course there was nearly 4k errors. Well, enough said, with a little hint from this old tutorial and a bit of trial and error, I managed to add this set of links under Debugging/Project properties/Configuration properties/VC++ directories/Header files directories:
Everything goes in promising direction, as errors number diminished from 4k to just one:
gtk-3.0\gtk\gtk.h: No such file or directory
No matter that this file is ACTUALLY in this location:
Regardless of combination of links in configuration above and using statement composition, compiler (?) can't find this damn file.
Please Halp
EDIT
I just confirmed, that it is indeed problem with target configuration. This is bad or good, depending on point of view. Good, because there is probably all good with VS setup. Bad, because I don't know a thing about compiling things under Linux.
On target (Raspberry Pi 3B) all ingredients for compilation are copied by Linux Development plugin. So in Terminal I executed line:
g++ main.cpp -o Blink2onRPi
and got
main.cpp:4:21: fatal error: gtk/gtk.h: no such file or directory
Now, I altered include line in main.cpp on target RPi, to this:
#include <gtk-3.0/gtk/gtk.h>
And now its missing <gdk/gdk.h>! When this change is made on host windows device - same result, but in VS.
As I dealt with similar problem in VS, upon setting links for IntelliSense (now apparently they're for this purpose), now probably similar dependencies have to be set somewhere on Raspbian. But where?
EDIT2
Upon execution of:
g++ main.cpp -o Blink2onRPi `pkg-config --cflags --libs gtk+-3.0`
on target RPi there is no more GTK-related errors, just wiringPi (also present in project) undefined references. It raises two possible questions:
1) How can I setup wiringPi on RPi so that the project could be manually compiled on target and
2) How/where add above line to Visual Studio, so it execute remotely with all GTK dependencies added properly on target
Researching stock present wiringPi library (as this is Blink led example for cross-compile Linux Development) I've found, that in Project Properties/Linker/Input/Library Dependencies there is mysterious entry:
wiringPi
Just that, nothing more. After removing this entry, on compilation pops out same errors as before on target (which apparently lacks proper wiringPi setup) - undefined references (not mensioned any missing headers). Can this be relevant for the case? If so, how could I add there such entry which would deal with missing GTK dependencies?
TL;DR
Use screenshot below to know where to add pkg-config calls in VS configuration so that it forwards it to the compiler and linker on the target.
Thanks to #zaguoba for providing these.
ORIGINAL ANSWER:
The list of directories to include is provided by pkg-config. For example pkg-config --cflags-only-I gtk+-3.0 will give you the list of include directories required. Those are the ones you need to add to the directories where VC++ wil look at include files. If you add the relative path you use in the #include, to one of those paths, you are able to find the file.
Example:
If you add to the directories C:\Program Files\foo\bar\gtk+-3.0
and have in your C file:
#include <gtk/gtk.h>
then the compiler will look for C:\Program Files\foo\bar\gtk+-3.0\gtk\gtk.h.
EDIT:
This all means the 'file not found' errors are because you're really building on the target and the target has no idea what C:\Program Files\... means. Those should be paths on the target filesystem, where the compiler is called. And this is exactly what pkg-config provides.
The copy of those files on the Windows machine filesystems is merely for Intellisense use, not for compiler use.
EDIT 2:
So that's that Visual Studio 2017 Community Linux Development plugin is what need to be undestood. It's not for cross compilation from Windows to Linux, istead it merely synchronizes code to the Windows host (for Intellisense use), but builds on the target. This means that all the paths and commands are Linux paths and commands, run on the target.
Here's the OP working configuration:
With that setup, you should
#include <gtk\gtk.h>
instead of
#include <gtk-3.0\gtk\gtk.h>
Alternatively remove all those VC++ directories/Header files directories, and just keep one of them that ends with include/ instead of listing up all the sub directiores.

How do I install C packages on windows

I have to use LU decompostion to fit a simple model to some data (simulated) in C. An example of what I need to do is here:
However, I'm stuck with a more basic problem: how do I install packages in C and call them in my code?
I'm new in C and I'm used to R. But I have this assingment to do some tests about Matrix inversion, LU decomposision and the professor suggested using Lapack to easy things (thus, I don't need to code myself the LU decomposition etc.). But I don't know how to install the package and call it in my code, in order to use the functions of LAPACK.
I have a windows 7 64 bits and I'm using compiler Code Blocks 8.02
Thanks for any help.
Normally you don't "install" C libraries in that sense. Normally, in Windows you have three types of files. The header files, typically ending in .h, the dynamic library, .dll, and most likely some linker files (typically, .lib, .a or something). The linker and compiler will need to be able to find these files somewhere. Normally you set the include directory paths, and library directory paths.
E.g. Let's say you downloaded a library called foo, and you extract it to C:\foo.
In that folder, libfoo.a, foo.dll and foo.h reside. In Code::Blocks you will have to point include directory path to C:\foo and library path to C:\foo so that the linker and compiler know where to look for these files. Since you're linking against the foo library, you will also have to set -lfoo or something similiar in linker command line. This is GCC syntax, but I think Code::Blocks uses GCC compiler behind the scenes anyways.
In the C code you can just #include <foo.h> and the compiler will find it for you.
You need to install that library and it might actually supply a tool for that. Check their documentation (e.g. a file INSTALL or README in their distributed sources). If the library uses only headers you might only need to copy it's headers to some directory on your system, but their buildsystem might be able to do that for you.
Once that is done you would tell your IDE on where to look for the sources and if the library uses not just headers to link against the actual library file. See the documentation in the Code::Blocks Wiki on how this is done for some example cases and adapt for your library.
The simplest thing to do in your situation is to install Cygwin. You can use the setup.exe installer to install the GCC and the LAPACK libraries. When you want to use the LAPACK library, you will add the -llapack option to your GCC command line.

Resources