Linking SDL in Makefile on mac - c

I'm trying to learn how to use libraries when writing C code on my mac (not using Xcode). My understanding is that on macs, there is the Library/Frameworks folder where you can put common libraries that can be shared across different projects.
My goal at this point is to use the SDL library to open basic window and do nothing else, but I can't figure out how to utilize libraries on my mac. So to be very specific, I just want to have one file of application code that I have written called main.c and it will have this boilerplate SDL code:
#include "SDL2/SDL.h" // OR #include "SDL.h" (Not sure how the difference in path works)
int SCREEN_HEIGHT = 800;
int SCREEN_WIDTH = 600;
int main() {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("SDL Game", 0, 0,
SCREEN_HEIGHT, SCREEN_WIDTH, SDL_WINDOW_HIDDEN);
SDL_ShowWindow(window);
SDL_Event event;
int running = 1;
while(running) {
while(SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT) {
running = 0;
}
}
SDL_Delay( 32 );
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
I downloaded the development library for mac from the SDL website (https://www.libsdl.org/download-2.0.php) and moved the download to the /Library/Frameworks folder on my machine, just as SDL instructed. However I don't know what to do in my Makefile for the library to be included and linked and then compiled with my main.c file.
Here are some specifics of my laptop/compiler:
MacOS Bug Sur
Version 11.3.1
MacBook Pro (16-inch, 2019)
Processor: 2.3 GHz 8-Core Intel Core i9
Memory: 32 GB 2667 MHz DDR4
Startup Disk: Macintosh HD
Graphics: AMD Radeon Pro 5500M 8 GB
Apple clang version 12.0.5 (clang-1205.0.22.9)
Target: x86_64-apple-darwin20.4.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Can someone show me what an example of a very simple Makefile would look like to accomplish this goal??

If you work from the command line or with a properly configured IDE, you link (In GCC) with the -l(library name) flag. The library you want to link needs to be in some directory like /usr/lib, /usr/local/lib or some Libraries folder MacOS might have. If it's not there, then use the -L(path/to/lib/directory) to tell GCC where to find it, and then use -l(library name) flag again.
The library name should start with lib and either end with a .a or .so suffix. So if you wish to link to your own SDL2 library build:
gcc source.c -o mygame -Llibraries/ -lSDL2
Assuming that the library is under libraries/libSDL2.so (Numbers in the end don't matter).

Related

GCC can't find headers on Windows

I'm new in winAPI and I was learning how code programs with some special functions and such, so I downloaded the Windows's SDK.
Problem is, GCC decided to put the blind glasses and say:
Documents_path.c:6:25: fatal error: KnownFolders.h: No such file or directory
#include<KnownFolders.h>
^
compilation terminated.
I said "OK, next one then" and there's another header with the same problem:
thread.c:3:30: fatal error: processthreadsapi.h: No such file or directory
#include<processthreadsapi.h>
^
compilation terminated.
I checked if these headers are even in my PC and here they are setting with windows.h, which it was working when I tried basic functions with it.
I searched an answer for this problem but didn't find any, either it was a external\binary libraries problem, is it local or not or a macro fix (which it didn't work).
How can I fix the problem?
EDIT:
I'm using VS Code
EDIT2:
This is the code of "Documents_path.c" example:
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<ShlObj.h>
#include<initguid.h>
#include<KnownFolders.h>
#pragma comment(lib, "user32.lib")
int main(){
int a;
PWSTR path = NULL;
HRESULT hr = SHGetKnownFolderPath(&FOLDERID_Documents, 0, NULL, &path);
if(SUCCEEDED(hr)){
printf("path for Documents is: %ls", path);
}
scanf("%d",&a);
CoTaskMemFree(path);
return 0;
}
And I'm reading the basics of winAPI from this website:
https://zetcode.com/gui/winapi/
as for structure of project folder:
C:\Users\ %USER%\Documents\C\dawd
MSVC uses Windows SDK while GCC does not.
On Windows GCC uses MinGW or MinGW-w64 as standard library, which is an open source implementation of Windows API.
So GCC+MinGW will use its own headers and will not look for any Windows SDK. So GCC+MinGW on Windows works without having any Microsoft developer tools installed at all.
MinGW-w64 - which is more recent than MinGW and which supports both Windows 32-bit and 64-bit - exists in a standalone package that can be downloaded from https://winlibs.com/. But you can still use it from an IDE like VSCode or Code::Blocks.
MinGW-w64 has the files like knownfolders.h and processthreadsapi.h which you had issues with.
But be aware that #pragma comment(lib, "user32.lib") is MSVC-specific and will not work in other compilers like GCC. Instead you must use linker flag -luser32. Because you call CoTaskMemFree() you will also need to add -lole32.
I tried your code on my system and it compiles and links fine with:
gcc -c -o Documents_path.o Documents_path.c
gcc -o Documents_path.exe Documents_path.o -luser32 -lole32

Can you have multiple DLLs with common exports/ordinals and exchange at run-time?

I am trying to create a couple of Win32 64-bit DLLs (Windows 10) which have different implementations but consistent symbol exports. The aim for this is that one would link with whichever one at build time but have the option at deployment to install either DLL and correctly run with that. I have achieved this straightforwardly on Linux where I am much more comfortable and familiar with run-time linking. But on Windows, I have not yet managed this and I am wondering if this is possible at all. I am trying this using both VS2010 and VS2019.
Suppose I have two libraries blah_legacy.dll and blah_modern.dll. They both export 6 symbols which are the interface to using the library, e.g. blah_open, blah_read, blah_write, blah_close, blah_control, blah_status.
I can link with the import library for either blah implementation and a test program calling each symbol loads and executes correctly with the corresponding blah DLL.
However, I cannot yet switch the DLLs at run time. For example, should I actually be able to link with blah-legacy.lib and then run with blah-modern.dll if I rename it to blah-legacy.dll? (Or vice-versa.)
I already got around basic file-naming issues and ensured the DLL needed can actually be found. I still got the application failed to start (0x22).
I used "objdump -xs" on the DLLs and noticed the order of symbols and their ordinals are different. So I created a .def file and ensured that the exported symbols match in number, names and in ordinals. Still nothing - the same error occurs.
There's still something to this I clearly have not figured out and would appreciate some guidance. Is this actually possible? Where do I start to look (which tools) to figure out what step to take next.
Yes.
I don't use Visual Studio much, but this is the kind of thing that happens all the time if you use MSYS2, and install some MinGW packages, and update them.
Here's what I mean by that: MSYS2 is an open source software distribution for Windows that, among other things, provides a bunch of native Windows software packages. The package manager (pacman) let's you choose which packages to have in your system, and it downloads DLLs and EXEs that were created by the MSYS2 developers. When an MSYS2 developer updates a library, you can download the updated library package, and all the other packages using that library will automatically start using the new DLL. Usually there is no issue with that because the new library version will be ABI-compatible with the old library version.
You do not need to use LoadLibrary or otherwise mess up your source code; the linker and the operating system should be able to take care of this for you.
Example
Here is a minimal example I threw together with MSYS2 showing how this can work.
The file foo_legacy.c represents your legacy DLL. I added some extra symbols so it wouldn't be too similar to the modern DLL.
__declspec(dllexport) int eoo() {
return 0;
}
__declspec(dllexport) const char * foo_name() {
return "legacy";
}
__declspec(dllexport) int foo_version() {
return 1;
}
__declspec(dllexport) int goo() {
return 0;
}
The file foo_modern.c represents the modern implementation:
__declspec(dllexport) const char * foo_name(void);
__declspec(dllexport) int foo_version(void);
int foo_version() {
return 2;
}
const char * foo_name() {
return "modern";
}
The file main.c represents an application using the foo API:
#include <stdio.h>
__declspec(dllimport) const char * foo_name(void);
__declspec(dllimport) int foo_version(void);
int main()
{
printf("%s %d\n", foo_name(), foo_version());
}
My build.sh file is a Bash script that builds and tests everything:
#!/usr/bin/bash
set -uex
gcc -Wall foo_legacy.c -shared -o foo_legacy.dll
gcc -Wall foo_modern.c -shared -o foo_modern.dll
gcc -Wall -c main.c -I. -o main.o
gcc main.o foo_legacy.dll -o main.exe
./main.exe # output: "legacy 1"
mv foo_modern.dll foo_legacy.dll
./main.exe # output: "modern 2"
rm foo_legacy.dll
./main.exe # fails because foo_legacy.dll is not found
The build script runs main.exe three different times, showing that it can either use the legacy DLL, or use the modern DLL, or fail, depending on what was installed in foo_legacy.dll.

How can I add a library I downloaded to my C compiler?

I've downloaded CSFML from github and would like to use it in one of my programs. How can I do so? I have a source folder containing some header files. It has three sub-folders.
include
lib
share
CSFML is the C-binding to SFML, which itself is a cross-platform multimedia framework.
Instructions for macOS
The instructions differ depending on the platform. Also whether you want to install them system-wide or have the bindings in a separate folder (e.g. if you play around with different versions of the bindings). There are also many different ways to use it from different development environments or build systems.
Here for example instructions on how to use it on the command line under macOS. The following instructions may therefore not fit your needs exactly, but should at least make the start easier.
Install SFML
Because CSFML is only a C binding to SFML, you must first download and install SFML.
For macOS you can get it from here: https://www.sfml-dev.org/files/SFML-2.5.1-macOS-clang.tar.gz
Due to https://www.sfml-dev.org/tutorials/2.5/start-osx.php#installing-sfml you need to:
Copy the content of Frameworks to /Library/Frameworks
...
Copy the content of extlibs to /Library/Frameworks
Project Structure
There are also different ways to set up a project structure, e.g. you could simply put your include, lib, and share directory in a subdirectory with the actual name csfml.
Then create a test.c file.
Building
You can then build your test program like this:
gcc -Wall -Wextra -I./csfml/include -L./csfml/lib test.c -lcsfml-graphics -lcsfml-window -o test
-I tells the compiler to look for include files in csfml/include, while -L tells the linker to look for the csfml-graphics and csfml-window libraries in the csfml/lib folder.
Dynamic Link Path
If you try to run the ./test executable, it will tell you that it cannot find libcsfml-graphics.dylib. To allow the dynamic linker to find the library at runtime, you can specify the path as follows:
export DYLD_LIBRARY_PATH=./csfml/lib
Then a call to ./test would actually run the program under macOS.
Test Program
For the sake of completeness: a simple test program drawing a red circle with a white border on a black background would look like this:
#include <SFML/Window.h>
#include <SFML/Graphics.h>
int main() {
sfVideoMode mode = {640, 640, 32};
sfRenderWindow *window = sfRenderWindow_create(mode, "csfml quick test", sfResize | sfClose, NULL);
sfCircleShape *circle = sfCircleShape_create();
sfCircleShape_setRadius(circle, 320.0f);
sfCircleShape_setFillColor(circle, sfRed);
sfCircleShape_setOutlineColor(circle, sfWhite);
sfCircleShape_setOutlineThickness(circle, 1.0f);
while (sfRenderWindow_isOpen(window)) {
sfEvent event;
while (sfRenderWindow_pollEvent(window, &event)) {
if (event.type == sfEvtClosed) {
sfRenderWindow_close(window);
}
}
sfRenderWindow_clear(window, sfBlack);
sfRenderWindow_drawCircleShape(window, circle, NULL);
sfRenderWindow_display(window);
}
return 0;
}

How to setup a cmocka example with arm-none-eabi-gcc + cmake?

I am developing firmware for stm32f4xx based systems.
For that I setup a toolchain based on the arm-none-eabi-gcc toolchain form ARM and cmake.
This toolchain works on Ubuntu. I can x-compile and debug(via openocd + eclipse IDE).
Now I like to add do some functional testing for my code. I was checking and it seems that cmocka is a good tool to use for embedded software testing.
I am now looking for an example/template that integrates a test into the cmake build.
let's assume a simple function at myfunc.c
#include "myFunc.h"
int buffer[10];
void myFunc(int i, int val) {
buffer[i] = val;
}
if I got it right I can do a test in a separate c file like "test.c"
#include "myFunc.h"
#include <cmocka.h>
// function success
static void test_myFunc_positive() {
for(int i = 0; i < 10; i++) {
myFunc(i,i);
}
}
static void test_myFunc_outofbounds() {
myFunc(100,44);
}
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_myFunc_positive),
cmocka_unit_test(test_myFunc_outofbounds),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
Usually I run
cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE="cmake/STM32Toolchain.cmake"
My question contains some sub questions:
1.) I installed libcmocka-dev. This is for my host system. Do I need to install cmocka for my arm-none-eabi-gcc compiler?
2.) How to setup cmake to pick the cmocka lib, build the test and run it on the host system? Think my toolchain file needs to be ignored.
Your source code looks pretty fine. Here is a recipe of how you could use cmocka.
I recommend to crosscompile cmocka's source code, too. In fact I doing it in this way:
Add cmocka.c to your sources
Add 'cmocka.h and cmocka_pbc.h and cmocka_private.h to your include directories.
Compile and run your software
PS: I don't know libcmocka-dev. I think this is a precompiled version of cmocka?
PPS: I had some trouble on getting cmocka's output redirected to my serial UART. If you're having the same problems, feel free to ask.

Ruby C Extension on Windows

I've been practicing with writing C extensions for Ruby. It works perfectly on Ubuntu and even when I tried linking to an third party library in my case I used SDL2 and it worked just fine on Ubuntu. When I'm writing C extensions for Ruby on Windows it compiles just fine I get my .so file and everything no errors. But when I test require like this ruby -I. -e "require 'gsdl'" I get an error saying "The specified module could not be found." Why is this how can I get the C extensions to work.
I have Devkit installed and I used Msys and the make that was included in Devkit's bin folder to make the c extention in my project /ext file. My extconf looks like this
require "mkmf"
ext_nme = "gsdl"
dir_config(ext_nme,"C:/Users/my_name/gsdl/SDL/include/SDL2","C:/Users/my_name/gsdl/SDL/lib")
have_library("mingw32")
have_library("SDL2main")
have_library("SDL2")
create_makefile(ext_nme)
and my C extention looks like this
#include <ruby.h>
#include "SDL.h"
void Init_gsdl(VALUE self);
void Init_gsdl(VALUE self){
SDL_Window* window;
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("Strawberry",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,240,240,SDL_WINDOW_SHOWN);
SDL_Delay(3000);
SDL_DestroyWindow(window);
puts("Gehirn SDL");
SDL_Quit();
}

Resources