/* cc -o vkdlopen -Os -Wl,-s -ldl vkdlopen.c */

#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <dlfcn.h>

#include <vulkan/vulkan.h>
#include <vulkan/vk_enum_string_helper.h>

struct Vulkan {
	void *__dl;
#define VULKAN_PFN(x) PFN_vk##x x
	VULKAN_PFN(CreateInstance);
};

void *vkopen(struct Vulkan *const vk)
{
	if( (vk->__dl= dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE)) ){
		vk->CreateInstance = dlsym(vk->__dl, "vkCreateInstance");
	}
	return vk->__dl;
}

int main(int argc, char *argv[])
{
	fputs("Press any key to load `libvulkan.so`... ", stderr);
	getchar();

	fputs("Loading `libvulkan.so`... ", stderr);
	struct Vulkan vk;
	void *const libvulkan = vkopen(&vk);
	if( !libvulkan ){
		fprintf(stderr,
			"failed with error %s\n",
			dlerror() );
		return EXIT_FAILURE;
	}
	fputs("done!\n", stderr);

	fputs("Press any key to create Vulkan instance... ", stderr);
	getchar();

	fputs("Creating Vulkan instance... ", stderr);
	VkInstance instance; VkResult rc;
	if( VK_SUCCESS != (rc=
		vk.CreateInstance(
			&(struct VkInstanceCreateInfo){
				VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, NULL,
				.pApplicationInfo = &(struct VkApplicationInfo){
					VK_STRUCTURE_TYPE_APPLICATION_INFO, NULL,
					.apiVersion = VK_API_VERSION_1_1,
				}, .flags = 0,
				.enabledLayerCount     = 0, .ppEnabledLayerNames     = NULL,
				.enabledExtensionCount = 0, .ppEnabledExtensionNames = NULL,
			}, NULL, &instance)
	)){
		fprintf(stderr,
			"failed with error %s (0x%x)\n",
			string_VkResult(rc),(unsigned)rc );
		return EXIT_FAILURE;
	}
	fputs("done!\n", stderr);

	fputs("Press any key to exit... ", stderr);
	getchar();
	fputs("Good bye!\n", stderr);
	return EXIT_SUCCESS;
}

