How to Make Lua in subdirectory of a larger project autoconf? - c

I have a C project I want to integrate with Lua.
This project has to be built on multiple platforms, so I want to build Lua in-tree with the rest of the C code, instead of depending on the system's Lua installation. Previously, we were using ax_lua macro to configure the system's Lua dependency, but I want to remove it and build Lua with the rest.
Unlike the other parts of the project, Lua already has a Makefile, and I don't want to convert this to Makefile.am just to get it converted back to Makefile.in then Makefile (unless, this is the only way.) Rather, I'd want something to the effect of running make inside the Lua folder and the rest of the build to proceed with the appropriate env vars (LUA_INCLUDE, LUA_FLAGS, LUA) set. To which files (configure.ac or Makefile.am) and what lines should I add to?
project/
lua-5.3.6/
Makefile
src/
a.c
b.c
configure.ac
Makefile.am
...

Rather, I'd want something to the effect of running make inside the
Lua folder and the rest of the build to proceed with the appropriate
env vars (LUA_INCLUDE, LUA_FLAGS, LUA) set. To which files
(configure.ac or Makefile.am) and what lines should I add to?
Unless you are willing to do it manually, it doesn't fit very well to try to build Lua before configuring the project. Moreover, even if you did build Lua manually in advance, unless you also installed it to the build system, it would be pretty optimistic to suppose that the macros from ax_lua would work as intended.
If instead you are content to build Lua via a recursive make during the overall project build, however, then the thing you're looking for is Automake's SUBDIRS variable. As its documentation describes, the subdirectories to be built do not have to be Automake-based. They just have to have makefiles (after configuration). The documentation also lists which targets the top-level makefile might try to build in the subdirectory, but it's not necessarily a showstopper if the subdirectory makefile does not support all of them. You would add this to your Makefile.am:
SUBDIRS = lua-5.3.6
The environment variables are a different question, whose answer depends in part on how the project depends on them. Probably you can just set the one you need (as make variables) in your Makefile.am. Since you are taking control of the Lua build, you can determine the needed values in advance. Everything in your Makefile.am is copied into the configured Makefile, so you don't need to do more to get those variables to the ultimate make.
For example, something along these lines might suffice:
LUA_INCLUDE = -I$(srcdir)/lua-5.3.6
LUA_LIB = lua-5.3.6/liblua-5.3.6.a
You might also consider dumping the variables in favor of just hardcoding the values, which, after all, will no longer vary.

Related

How does CMake add_executable work internally (dependencies and automatic source discovery)?

I am working on my first CMake/C project and I crossed a problem with my build that makes me re-question how compilation work.
I would like people to explain to me what exactly happens when you call add_executable and how make builds C file dependencies.
What I thought
I thought that, when calling add_executable (name, sources), CMake would see sources as a superset of the necessary source files to build the target name. So internally, he analyzes the REAL MINIMAL dependencies, by analyzing the file containing main, and recursively adding the included .h files, with their associated declarations in the .c files.
What seem to happen (I want confirmation)
CMake sees sources as the real minimum dependencies for the executable. It seems it will compile ANYTHING in sources, whether or not it is used anywhere.
Consequence
This for me is really annoying. In my project I use source discovery, meaning that anything in the src directory is added to the sources. Then, if I want to compile a unit test (make this_unit_test), it is, in fact, going to compile every .o file in my source directory instead of compiling the necessary files only. Which means that if something does not build in a part of my project, I can not build any tests anymore.
What can I do?
If CMake is indeed done in a way that you need to specify yourself the minimal dependencies for any executable, how can I still use automatic source/test discovery? The best solution would be from the CMakeList file, a function that takes a list of source files, and return the subset of it corresponding to what is actually included at some point by the file containing main. What do people do to resolve that problem?
No, CMake does not scan for minimal source dependencies for your executable, and how could it? CMake doesn't scan the source files, and has no knowledge about what includes/definitions your executable ultimately needs or doesn't need. This functionality would have to happen at the compilation stage (after CMake completes), because it is the pre-processor/compiler that parses your source files and interprets them for semantics (meaning). There are static analysis tools out there that can help achieve something like this, such as include-what-you-use.
Using source discovery techniques in CMake (such as file(GLOB ...)) can be error prone:
As you have seen, the source discovery mechanism may grab files that you do not need for building a particular target.
Even worse, source discovery may leave out files that are required for building a particular target.
The CMake documentation itself even warns against doing this!
Note: We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.
As a general rule of thumb, it is always safest to list each individual file that is required for each target explicitly, for example:
add_executable(MyExe
main.c
MyHelperFunctions.c
MyOtherStructs.c
)

Compile entire C project instead of few files

I have an entire library made in C. It has almost 10 folders with a lot of files.
I have created a filename.c file in root folder and trying to compile it in mac using gcc test.c -o test however its not including header files. Generally I have to add all the header files gcc test.c libaudio.c -o test
How can I compile entire project instead of just one file.
Makefiles will solve your problem. You can create your own rules to clear the project (remove the generated files), build the project indicating where is your compiler (compile the source files located in some specific path, extension, etc), set the output path and so on, without typing a large compilation order.
https://www.gnu.org/software/make/manual/make.html
Edit: There you will be able to find how to add shared, static or raw libraries to your proyect through makefiles.
Use a Makefile. make the utility the reads the configuration within the Makefile will automate the running of the individual commands, such that you only need to name the item you wish to be rebuilt.
make myprogram
And make will use the dependency information stored in the Makefile's rules to determine what other elements are "out of date", rebuilding those and assembling them into myprogram.
This is a decent "first time" tutorial for "make".
Here is the full blown documentation for "make"
Once you master the concepts within make, you can then use other tools that make maintaining Makefiles either easier, more portable, or both.
Some tools that improve upon "make" include "cmake", "automake", "the autotools collection", "scons", "waf", "rake", "doit", "ninja", "tup", "redo", and "sake". There are more, and some are programming language specific, or limited to a particular enviornment.
The reason I recommend "make" over the others is because "make" is a baseline that will always be present, and the features in the other tools are often not understood or recognized to be needed until you get enough experience with "make".
In C, the concept of project is not part of the language, it depends generally of the tools / platform / library you have to build.
On Linux based platforms, you may have a makefile describing the project, or the library may have a cmake script.
You should be able to find the build instructions in you library documentation.
I definitely recommend the make approach as it is scalable.
If you really only have a couple of files, gcc will accept multiple .c files on the command line and link them all to generate one executable.

Virtual environment for C library development

Original
I am looking for a way to create a non-isolated development environment for a C-library.
I will most likely use cmake to build the library and my IDE is a simple text editor.
The problem now is that I do not only create the library but also some sample "applications" using the library.
Therefore I need to install the library's headers and the shared object (I'm using GNU/Linux) somewhere and I do not want to install it to /usr/local/lib or (the even worse) /usr/lib.
Is there a way to create a virtual environment similar to python's pyvenv (and similar) where I can install the everything to but still have access to the host libraries?
Also I do not want to rewrite my $PATH/$LD_LIBRARY_PATH, setup a VM, container, or chroot.
The usage would then look like:
# switch to environment somehow
loadenv library1
# for library
cd library
make && make install
# for application
cd ../application1
make && ./application1
Is this possible?
Edit 1
So basically my directory structure will look like this:
library/
library/src/
library/src/<files>.c
library/include/<files>.h
application/
application/src/
application/src/<files>.c
First I need to compile the library and install the binary and header files.
These should be installed in a fake system-location.
Then I can compile the application and run it.
Edit 2
I thought a bit about it and it seems all I need is a filesystem sandbox.
So basically I want to open up a shell where every write to disk is not committed to the filesystem but rather temporarily saved in e.g. a ramfs/tmpfs just to be dropped when the shell exits.
This way I can exactly test how everything would behave if compiled, deployed and executed on the real machine without any danger to existing files or directories and without accidentally creating files or directories without cleaning them up.
You don't really need to 'install' the library, you can work in the development tree.
(1) for compilation all you need to do is use -I flag to specify where the libraries header files are, and this can be a relative path, for example in your case you could do -I../../library/include
(2) for linking you need to tell the linker where the library is located at, you can use the -L flag append to the library search order.
(3) for testing the application, you are correct that the application needs to be able to find the library. You have a couple of options:
(a) make sure the library and the executable are in the same directory
(b) you can temporarily modify your LD_LIBRARY_PATH, in your current shell only, for testing:
export LD_LIBRARY_PATH=abs_path_to_library:$LD_LIBRARY_PATH
note that this will only effect the current shell (command terminal) you are working in. Any other shells you may have open, or open later will have your normal LD_LIBRARY_PATH. I know you specified that you don't want to modify your PATH or LD_LIBRARY_PATH, but being local to the shell that the command is executed it is a nice, easy way to do this.
(c) embed the path to the library in the client executable. To do this you need to pass an option to the linker. The command for gcc is:
-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)
see this how-to

Best practices for structuring a C program (for CMake build)

I have a C program that was handed down to me by a developer who left. I am trying to figure out exactly what he had goign on and get the software re-arranged into something more logical so I can build it easier. I am using CMake to build, whereas he was using Make.
There is one src/ folder that had several source files in it, and out of those, about 4 had main() methods. The files with the main() methods are in files that are named more as if they are utilities, or tools, or whatever. This kind of strikes me as odd, because he also had a lib folder, with some other things in it that were built and looked more like libraries. Should I split out those main methods into "driver" source files, and make the methods that are also defined in those files to be other libraries? If I do this, I know how to make CMake go look for a library and build and link it to the driver for execution.
If it is acceptable to build those "library" source files where they are, in the src folder, should I just set CMake up to build everything in that folder all at once, or should I create a directory structure for at least some logical separation?
Just as an idea, here is the current directory structure
project
.../src
......file1.c
......file2.c <-has a main() as well as other methods
......file3.c
......file4.c <- has a main() as well as other methods
......file5.c
.../lib
....../lib1
........./file1.c <-references top level include folder files
........./file2.c
....../lib2
........./file1.c <-refs top level and local include files
........./file2.c
........./file2.h
.../scripts
.../include
.
.
.
Any advice on best practices for restructuring this build or configuring it in CMake is appreciated.
It's never too late for an answer, so I'd propose:
project
.../CMakeLists.txt
include_directories(include/)
add_subdirectory(lib/lib1)
add_subdirectory(lib/lib2)
add_subdirectory(src/)
.../lib/lib1/CMakeLists.txt
add_library(lib1 file1.c file2.c)
.../src/CMakeLists.txt
add_executable(test1 test1.c test2.c)
target_link_libraries(test1 lib1)
Why does it work: include_directories are derived in sub-directories, all targets (and thus libraries) from add_subdirectory are exported throughout the whole project.

Autocreate directories when building

I have a project written in C and I am using mercurial (I can use git too) for version control and GNU make for building. The project includes several empty directories used for build-time generated files, such as dependency makefiles and object files.
When I check out the project, however, empty directories are not created (they are ignored by the version control system) and the build fails.
The only remedy I have in mind is to add a mkdir -p directive in every single recipe in the 58 makefiles of the project (it is quite big). Apart from a lot of editing, mkdir -p is discouraged in the GNU make manual for being incompatible with other versions of make.
Is there any smarter way to overcome the problem?
Both git and Mercurial track files, not directories, so empty directories will not be stored.
The common trick is to just add an empty file to the directories you need, like:
touch output/.empty
And then add that to the repository.
You can have:
output/%: output/.empty
output/.empty:
$(MKDIR_P) output
touch output/.empty
in the makefile. Than all files in output will depend on creating the directory without modifying each rule separately.
The $(MKDIR_P) definition (mkdir -p for most systems or a special script where that does not work) can be provided by configuration script (e.g. autoconf using AC_PROG_MKDIR_P) or conditional setting in the makefile.
As you mention that you could use git as well, maybe that you would be interested by the fact that bazaar can track directories the same way it does for files. I don't know if it is an option for you, just saying.

Resources