Previously, I'm looking for this kind of question but none of them are working as example this thread and this one.
Currently, I'm creating a C library which supposed to outputs a shared library (*.so or *.dll) file and multiple *.h files in a ./include directory. The shared library is successfully built and installed to /usr/local/lib. However, I have no idea how do I tell CMake to copy *.h files to the correct destination as below.
In POSIX: /usr/local/include
In Windows: C:\<Compiler Path>\include
I know I could workaround this by copying those *.h with Python script or using if-else logic on CMake. But at least tell me if there is a feature in CMake for doing that thing. Thanks!
Here's my CMakeLists.txt:
cmake_minimum_required(VERSION 3.12)
project (
learn_c_library
VERSION 1.0.0
LANGUAGES C
)
# Specify CMake build and output directory
set(CMAKE_BINARY_DIR "${PROJECT_SOURCE_DIR}/.cmake")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/out")
# Use every .c file inside ./src
file(GLOB_RECURSE MY_SOURCE_PATH "src/*")
add_library(
${PROJECT_NAME} SHARED
${MY_SOURCE_PATH}
)
include_directories(
${PROJECT_NAME}
"include/"
)
# Allows "make install" to install shared library
install(TARGETS ${PROJECT_NAME})
This answer improves on your answer:
cmake_minimum_required(VERSION 3.14)
# ...
include(GNUInstallDirs)
install(DIRECTORY "include/"
TYPE INCLUDE
COMPONENT MyProj_Development)
The GNUInstallDirs module provides standard configuration points for customizing a project's install layout. These variables should essentially always be used instead of hardcoding path/directory names.
The TYPE INCLUDE argument to install() was introduced in CMake 3.14 and uses GNUInstallDirs's CMAKE_INSTALL_INCLUDEDIR variable to determine the destination.
Finally, and especially if your project is a library, all your install() rules should be given a COMPONENT argument to allow splitting files between runtime and development packages (and potentially others like documentation and architecture-independent data files).
After days of fiddling CMake, finally I found the solution!
Let's assume you store your public *.h inside ./include directory, then here's the syntax for installing your *.h files to your machine:
install(
DIRECTORY
"include/" # Your global headers location in the project
DESTINATION
include # This is your system's default "include" location
)
I got the solution from here with usr/myproject replaced to be include
I've recently moved over to CodeLite for C development, and i've been trying to get sigil to work for MinGW32.
I've been trying to include it locally from the project settings using the path F:/sigil-mingw32, where the library is located.
I have the parameter "Compiler/ Include Paths" set to F:/sigil-mingw32/include
And my linker path in "Linker/ Libraries Search Path" set to F:/sigil-mingw32/lib respectively.
I've set my "Linker/ Libraries" to include the library "libsigil.dll.a", But when i build my project i get the output:
c:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -l-libsigil.dll
And then the build fails.
Why is the linker excluding the .a suffix from the library dll file?
Turns out that CodeLite can directly link imported libraries without having to add the full path into your linker settings. Unlike in CodeBlocks, the linker will not remove the "lib" prefix in dll.a libraries when given a direct path to the library file.
So instead of "path/lib/libsigil.dll.a" Only the location of the library folder is provided in Linker/Libraries Search Path and the Libraries parameter will be passed to gcc directly, which excludes the "lib" prefix.
So setting the parameter as "sigil" instead of "libsigil.dll.a" is enough.
I currently have two C projects on Clion with cmake. One of the projects is named "sharedLibsDemo" and I am trying to create a shared library in this project. In the other project I want to use the library that was created by the "shared" project.
Currently, in the "sharedLibsDemo" project I have the following cmake:
cmake_minimum_required(VERSION 3.7)
project(sharedLibsDemo)
set(CMAKE_C_STANDARD 11)
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}")
set(SOURCE_FILES shared.c shared.h main.c)
add_library(shared SHARED ${SOURCE_FILES})
include(GenerateExportHeader)
GENERATE_EXPORT_HEADER(shared # generates the export header shared_EXPORTS.h automatically
BASE_NAME shared
EXPORT_MACRO_NAME SHARED_EXPORTS
EXPORT_FILE_NAME shared_EXPORTS.h
STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC)
set(EXEC_FILES main.c)
add_executable(myexe ${EXEC_FILES})
target_link_libraries(myexe shared)
However, this cmake only creates the shared_EXPORTS.h, libshared.dll, and libshared.dll.a` files.
I managed to create the .lib file using Mingw itself and put all of these files including the .h file of the source code into one folder and placed the folder in the root folder of the second project in order to use it.
However, I've looked everywhere to find a way to link the library into the second project's executable. The documentation for cmake itself assumes I have a tonne of knowledge which I don't. Is there any list of commands that I can use to finally link my library. I have already tried the generic answer of "use find_package() or target_link_libraries" to no avail.
EDIT 1
The following is the contents of shared.h :
#include "shared_EXPORTS.h"
#ifndef SHAREDLIBSDEMO_LIBRARY_H
#define SHAREDLIBSDEMO_LIBRARY_H
void SHARED_EXPORTS sharedHello(void);
#endif
As per the suggestion of #Shmuel H. I placed the shared.h shared.c and the cmakelist.txt for the shared project into a folder in the project that I want to include the library in. And I used add_subdirectory() and target_link_libraries().
The following is the CMakeLists.txt for the project:
cmake_minimum_required(VERSION 3.7)
project(projectFiles)
set(CMAKE_C_STANDARD 11)
include_directories(src ${maker_INCLUDE_DIR})
set(SOURCE_FILES src/nv_runner/main.c src/FactParser/FactParser.c src/FactParser/FactParser.h src/Utils/Utils.c src/Utils/Utils.h src/nv_runner/main.h)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
find_package(maker REQUIRED)
include_directories(${maker_INCLUDE_DIR})
set(LIBSHARED_LOCATION ${PROJECT_SOURCE_DIR}/libshared)
add_subdirectory(libshared)
include_directories(${LIBSHARED_LOCATION})
add_executable(${PROJECT_NAME} ${SOURCE_FILES} src/FactParser/FactParser.c src/FactParser/FactParser.c src/FactParser/FactParser.h src/nv_runner/main.h)
target_link_libraries(${PROJECT_NAME} ${maker_LIBRARY})
target_link_libraries(${PROJECT_NAME} shared)
At first, I had to remove the SHARED_EXPORTS macro from the sharedHello function and the shared_EXPORTS.h include in shared.h because otherwise it would not recognize the function for use in other files. But when I ran the program I got this result:
Process finished with exit code -1073741515 (0xC0000135)
EDIT 2
Project setup image
In the screenshot, I've taken all the necessary files from the shared project, placed it in a directory in the current project and marked the directory as a Library. The cmake can be seen in the image. With this setup, whenever I run my program, it just crashes with the error seen in the image.
I found out what the issue was. I did not know that the dll had to be in the same folder as the exe, that's why the program was not executing. Once I placed the .dll file inside the exe folder, it worked.
Credit goes to this question for helping me identify the issue: C++ running file with included library failes without compiling error (CMake / CLion)
And I found out that .lib files are only necessary for MSVC compiler. MinGW uses the .dll.a file; replacing .lib. This post lead me to finding this out: Compatibility of *.dll *.a *.lib *.def between VisualStudio and gcc
Please correct me if I'm wrong however. Here is an image of my current project and cmake setup
I've created a simple project to learn how to create a static library. I've created a new workspace in CodeLite and a new project and a new static library.
In the static library I've got, inside a "include" folder a .h file called helloworld.h and inside a "src" folder a .c file called helloworld.c. The output files are generated in a folder inside the workspace in a folder called lib (../lib).
Inside the same workspace I have a project with a file .c where the helloworld is called with #include "helloworld.h". Finally, the settings of the project are:
linker menu:
Libraries search path: ../lib
Libraries:
General Menu:
When I compile the project I got the following error:
fatal error: 'helloworld.h' file not found
The only way that the project compiles without problems is to get the relative path to the file within the include parameter:
#include "../HelloWorldLib/include/helloworld.h"
I wonder if there is a way to work without having to add the path to the file. I'm using CodeLite in MAC OS 10.9.5. The same problem occurs in Ubuntu.
My teacher explained that this does not occur in CodeLite Windows, but he doesn't know what could be happening in Mac. Moreover, it should not be necessary to use the path within the include parameter.
If you go to the "Compiler" tab instead of the "Linker" tab, try adding your 'include' directory under the "Include Paths" option.
I'm sure this question has been asked many times, but I can't figure this out. Bear with me.
So when you download a library, you get a bunch of .c and .h files, plus a lot of other stuff. Now say you want to write a program using this library.
I copy all the .h files into my project directory. It just doesn't compile.
Great, so then I get the library as a bunch of .dll's, and i copy the dlls into my project directory. Still doesn't compile.
How does this work?
What do you do, like right after creating the folder for your project? What parts of the library package do you copy/paste into the folder? How do you make it so that it can compile? Go through the steps with me please.
Where to put the .h files?
Where to put the .dll files?
How to compile?
Thanks.
(the library I'm trying to get working is libpng, I'm in windows with MinGW, and i'm looking to compile from command-line like usual.)
(from what i gather, you put the .h files in directory A and the .dll files in directory B and you can use -l and -L compiler options to tell the compiler where to find them, is this correct?)
Here's a brief guide to what happens when you compile and build a basic C project:
The first stage compiles all your source files - this takes the source files you've written and translates them into what are called object files. At this stage the compiler needs to know the declaration of all functions you use in your code, even in external libraries, so you need to use #include to include the header files of whatever libraries you use. This also means that you need to tell the compiler the location of those header files. With GCC you can use the -I command line to feed in directories to be searched for header files.
The next stage is to link all the object files together into one executable. At this stage the linker needs to resolve the calls to external libraries. This means you need the library in object form. Most libraries will give you instructions on how to generate this or might supply it ready built. Under Linux the library file is often a .a or .so file, though it might just be a .o. Again you can feed the location of the library's object file to GCC with the -L option.
Thus your command line would look like this:
gcc myProg.c -I/path/to/libpng/include -L/path/to/libpng/lib -lpng -o myProg.exe
(Note that when using the -l command line GCC automatically adds lib to the start of the library, so -lpng causes libpng.a to be linked in.)
Hope that helps.
Doing it under windows (supposing you user Visual Studio)
After unpacking add the library include directories to your projects' settings (Project -> Properties -> C/C++ -> Additional Include Directories)
Do the same thing for the Libraries Directory (Project -> Properties -> Linker -> Additional Library Directories)
Specify the name of the library in your Linker Input: Project -> Properties -> Linker -> Input -> Additional Dependencies
After this hopefully should compile.
I don't recommend adding the directories above to the Global settings in Visual Studio (Tools -> Options -> Project and Solutions) since it will create and environment where something compiles on your computer and does NOT compile on another one.
Now, the hard way, doing it for a Makefile based build system:
Unpack your stuff
Specify the include directory under the -I g++ flag
Specify the Library directory under the -L g++ flag
Specify the libraries to use like: -llibrary name (for example: -lxml2 for libxml2.so)
Specify the static libraries like: library name.a
at the end you should have a command which is ugly and looks like:
g++ -I/work/my_library/include -L/work/my_library/lib -lmylib my_static.a -o appname_exe MYFILE.CPP
(the line above is not really tested just a general idea)
I recommend go, grab a template makefile from somewhere and add in all your stuff.
You must link against a .lib or something equivalent i.e. add the ".lib" to the libraries read by the linker. At least that's how it works under Linux... haven't done Windows so a long while.
The ".lib" contains symbols to data/functions inside the .dll shared library.
It depends on the library. For examples, some libraries contain precompiled binaries (e.g. dlls) and others you need to compile them yourself. You'd better see the library's documentation.
Basically, to compile you should:
(1) have the library's include (.h) file location in the compiler's include path,
(2) have the library stubs (.lib) location in the linker's library path, and have the linker reference the relevant library file.
In order to run the program you need to have the shared libraries (dlls) where the loader can see them, for example in your system32 directory.
There are two kinds of libraries: static and dynamic (or shared.)
Static libraries come in an object format and you link them directly into your application.
Shared or dynamic libraries reside in a seperate file (.dll or .so) which must be present at the time your application is run. They also come with object files you must link against your application, but in this case they contain nothing more than stubs that find and call the runtime binary (the .dll or the .so).
In either case, you must have some header files containing the signatures (declarations) of the library functions, else your code won't compile.
Some 'libraries' are header-only and you need do nothing more than include them. Some consist of header and source files. In that case you should compile and link the sources against your application just as you would do with a source file you wrote.
When you compile, assuming you have the libs and the headers in the same folder as the sources you are compiling, you need to add to your compile line -L . -I . -lpng. -L tells the linker where to look for the library, -I tells the compiler where to look for the headers and -lpng tells the linker to link with the png library.
[Edit]
Normal projects would have some sort of hierarchy where the headers are in an /include folder and the 3rd party libs are in a /libs folder. In this case, you'd put -I ./include and -L ./libs instead of -I . and -L.
[Edit2] Most projects make use of makefile in order to compile from the command line. You can only compile manually for a small number of files, it gets quite hectic after that
Also,
you may want to look over Dynamic Loading support in various languages and on various
platforms.
This support is very handy in cases when you want to use a library optionally and you don't want your program to fail in case that library is not available.