In my project I have made configure.ac and Makefile.am files correctly so my components compile and dynamically link to the appropriate libraries. One of these components links to a library that uses QT, so the appropriate Makefile must be generated out of the .pro file prior compilation on the target system.
For this I think that I need to find a way to tell my make scripts, through Makefile.am perhaps, that this library must be compiled on its own by first running qmake and the generated Makefile in that directory.
Is this even possible? If so, how do I do it?
Researching on my own I have found an apparently abandoned project called “AutoTroll” which is supposed to automatically alter files of autotools in order to add compatibility with Qt4. I have tried to make it work with no luck. It lacks a proper documentation also.
Without this tool, compiling Qt4 modules with autotools requires a lot of hacking and interventions, making it really hard and even more for a cross-platform application.
I have switched to CMake. CMake’s setup is far easier than autotools’ and it supports Qt4 modules out of the box.
We do this, its not that difficult. In configure.ac:
QT_QMAKE
[
echo $QMAKE -o Makefile.myapp $(realpath $(dirname $0))/myapp.pro
$QMAKE -o Makefile.myapp $(realpath $(dirname $0))/myapp.pro
]
Then (Assuming your macros are located in the standard m4 directory), make a file called qt_qmake.m4 there.
AC_DEFUN([OTT_QT_QMAKE],[
if test -z "$QMAKE"; then
QMAKE=$(which qmake)
$QMAKE -v > /dev/null 2>&1
if test $? -ne 0; then
AC_MSG_ERROR([qmake executable not found!])
fi
fi
AC_SUBST(QMAKE)
])
Then in Makefile.am:
ACLOCAL_AMFLAGS=-Im4
all-am:
make -f Makefile.myapp all
install-am:
make -f Makefile.myapp install
qmake_all:
make -f Makefile.myapp qmake_all
clean-am:
make -f Makefile.myapp clean
That should align with the targets that QTCreator uses, and allows you to "bootstrap" qmake using autotools to make a config.h for instance, or global qmake include file to make shadow builds easier. Theres a lot I'm leaving out if you want to have version checking,etc... but it should get you started. If you built qt yourself, or have it not in your path, ie redhat (/usr/lib{64}/qt5/bin/qmake), you can just use the QMAKE variable to point to it. QT is smart enough with that to take it from there usually. I know its not the most elegant solution, but its worked for us cross-linux for almost a decade.
Related
I wrote a small project in OCaml.
I have two folders:
./myUnionFind. inside there is a file myUnionFind.ml.
./percolation. inside there are two files: myPercolation.ml and percolation_stats.ml.
myUnionFind.ml works as a module.
myPercolation.ml works as a module too, but it uses MyUnionFind module defined in myUnionFind.ml.
percolation_stats.ml uses myPercolation.ml.
together with above all, I also use Batteries.
I want to compile them all to work and get a executable file run.
But how?
I have tried the following:
inside folder ./percolation, I did ocamlfind ocamlc -package batteries -linkpkg ../myUnionFind/myUnionFind.ml myPercolation.ml percolation_stats.ml -o run
It failed, and said File "myPercolation.ml", line 1, characters 0-16:
Error: Unbound module MyUnionFind, but I did include that folder ../myUnionFind, right?
Also, if I just want to compile ./myUnionFind/myUnionFind.ml once, how can I do so that not every time, myUnionFind.ml gets compiled again and again?
Inside myUnionFind, you should compile myUnionfind.ml to a compiled unit:
cd myUnionFind
ocamlc -c myUnionFind.ml
This will generate myUnionFind.cmo, which stores the compiled implementation, and myUnionFind.cmi, which stores the compiled interface. Other modules using MyUnionFind will need to access the cmi at type-checking type.
Inside percolation, you can compile myPercolation.ml to a module by doing
cd percolation
ocamlc -I ../myUnionFind -c myPercolation.ml
Again, you get both a .cmo and a .cmi. Note that the compiler has looked up myUnionFind.cmi automatically in the search path, and found it because of the -I option.
You can then compile percolation_stats (relying on both previous compilation units)
ocamlc -I ../myUnionFind -c percolation_stats.ml
You finally link the three resulting .cmo together to build an executable:
ocamlc ../myUnionFind.cmo myPercolation.cmo percolation_stats.cmo -o run
(If you use batteries, wrap each command with ocamlfind ocamlc -package batteries, but only the linking command with linkpkg).
To make this process simpler:
ocamlbuild is good at finding and compiling all the files of your current project to produce an executable. In the percolation directory, ocamlbuild percolation_stats.byte can produce an executable with all the stuff present
but if you want to use myUnionFind as an external library, the best thing to do would be to install it with findlib, to make it easy to find and specify from percolation; for information on how to create a findlib package (it's very simple), please see this older answer
once myUnionFind is a findlib package, the single command ocamlbuild -use-ocamlfind -pkgs batteries,my-union-find percolation_stats.byte (or .native) should be enough to get an executable
Is there an automated way to remove unnecessary targets from Makefile?
I used ones generated by qmake, but I am to run them on machine doesn't have QT. Since the Makefile generated by qmake, it contains QT-related targets such as 1) "Makefile:" that call "$(QMAKE)" 2) "qmake:" ; as well as QT files in dependencies, such as "/usr/share/qt4/mkspecs/common/g++.conf" and so on.
Makefile: my_project.pro /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mkspecs/common/g++.conf \
/usr/share/qt4/mkspecs/common/unix.conf \
...
$(QMAKE) -spec /usr/share/qt4/mkspecs/linux-g++ -unix CONFIG+=debug -o Makefile my_project.pro
...
qmake: FORCE
#$(QMAKE) -spec /usr/share/qt4/mkspecs/linux-g++ -unix CONFIG+=debug -o Makefile my_project.pro
I have tried to remove those targets by hand and than could successfully compile project with them. The question is if there a simple automated way?
No there isn't. If you are using qmake, it means that you want to use it on computers with qt installed. As far as i know you shouldn't share your sources with Makefile's but with .pro files only. Anyone compiling it for himself should call qmake before make (or 'nmake' if you are using visual).
If you are not using qt at all, and use only qmake to generate Makefile, then there are alternatives (although not as simple as qmake, I admit) such as cmake or autoconf/automake.
I've been reading for a couple days on how to copy/update external resources, plugins or frameworks to my App's Mac Bundle using Qt creator or qmake.
Right now I have found two main solutions. One is to use qmake together with some commands on the ".pro" file. The other one is to do a "Custom Deployment Step" script.
I was hoping to use the second option cause I already had a small make script that did what I wanted. The problem is that Qt Creator offers so little variables to work with that the script lost its usefulness. For instance, my script uses the "Target App Path" as a parameter so it can do all its work from there. But please correct me if I'm wrong, Qt Creator only offers %{buildDir} and %{sourceDir} variables...
The other option is using qmake. These are the things that I have tried so far on my ".pro" file:
1) Using the INSTALL command. I did a small test where I tried copying some files this way:
MediaFiles.path = test/media
MediaFiles.files = media/*
INSTALL += MediaFiles
And basically nothing happend. I was hopping to find the same "media" folder on the "test" folder but nothing. Don't know if I'm doing something wrong.
Please note that the "media" folder is beside the "test" folder and the ".pro" file. (They all have the same hierarchy position.)
2) Then I tried QMAKE_BUNDLE_DATA:
MediaFiles.path = Contents/MacOS
MediaFiles.files = media/*
QMAKE_BUNDLE_DATA += MediaFiles
But this gave me the following error:
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ... target_directory
make: *** [PathToApp] Error 64
None of the solutions seem to be pleasing so far. If I wanted to do a good custom make script I will need to hardcode every target path separately. In my case I have 8 different target path depending on some "CONFIG" variables.
I'm sure the qmake solution are the official way of doing this. If someone can point me out the solution to the Error 64 would be cool.
Some further question:
Do I have to do a qmake every time I want to update my bundle?
Can I execute my make script with the qmake?
QMAKE_BUNDLE_DATA started working flawlessly after putting the command on the end of the .pro script.
mac{
MediaFiles.files = media
MediaFiles.path = Contents/MacOS
QMAKE_BUNDLE_DATA += MediaFiles
}
This is my first try with cmake and I would like to have, if possible, some feedbacks about what I did since some problems remain.
In the CMakeLists.txt of the library folder, I created two makefile targets: configure-antlr3c and antlr3c. The first target runs the autotools configuration shell script, the second one runs the make executable to build the library:
# CMakeLists.txt in libantlr3c-3.1.3
add_custom_target(
configure-antlr3c
${SHELL_EXECUTABLE} configure
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_custom_target(
antlr3c
${MAKE}
DEPENDS configure-antlr3c
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
The main problem is thatconfigure-antlr3c target is always "out of date", so it will always be executed even if no changes happened. Moreover, I necessarily need to generate my cmake makefiles in a separate directory (not in the root directory of my project) to avoid overriding the autotools Makefile of the library...
Has anyone had this problem (building autotools projects with cmake) ? And if so, what have been your solutions ?
Thank you.
EDIT : Solution
In the root CMakeLists.txt:
include(ExternalProject)
ExternalProject_Add(
libantlr3c
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/libantlr3c-3.1.3
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/lib/libantlr3c-3.1.3/configure --prefix=${CMAKE_CURRENT_SOURCE_DIR}/lib/libantlr3c-3.1.3
PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/lib/libantlr3c-3.1.3
BUILD_COMMAND make
BUILD_IN_SOURCE 1
)
I think that you'd be better off using the ExternalProject feature of cmake. I guess you have your project and have libantrl in a sub directory?
project
+- libantlr
+- mysrc
---- etc ----
If that's the case, you can do something like this in the top level CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project(test)
include(ExternalProject)
ExternalProject_Add(libantlr
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libantlr
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/libantlr/configure --prefix=<INSTALL_DIR>
BUILD_COMMAND ${MAKE})
The <INSTALL_DIR> is expanded to something like libantlr-prefix, so things are installed in your build tree rather than in /usr/local, which is what autotools would do without a prefix.
I needed to do something similar but found it surprisingly difficult to get a working solution, despite the example provided here with the accepted answer, and code snippets provided in several other blog posts, the CMake support email listserv archives, etc. For the benefit of others who come across this question, here is my solution.
The external project we wanted to use is libmodbus, though I believe my solution is general enough to work with any project configured with the standard autoconf recipe of ./autoconf.sh && configure.sh && make && make install.
We wanted to add libmodbus as a submodule of our git repository. We added to our repository at the path <root>/opt/libmodbus. The CMake code to configure it is located in <root>/cmake/modbus.cmake, which is included from our root CMakeLists.txt using
# libmodbus
include(cmake/modbus.cmake)
The content of cmake/modbus.cmake is:
include(ExternalProject)
set(MODBUS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/opt/libmodbus)
set(MODBUS_BIN ${CMAKE_CURRENT_BINARY_DIR}/libmodbus)
set(MODBUS_STATIC_LIB ${MODBUS_BIN}/lib/libmodbus.a)
set(MODBUS_INCLUDES ${MODBUS_BIN}/include)
file(MAKE_DIRECTORY ${MODBUS_INCLUDES})
ExternalProject_Add(
libmodbus
PREFIX ${MODBUS_BIN}
SOURCE_DIR ${MODBUS_DIR}
DOWNLOAD_COMMAND cd ${MODBUS_DIR} && git clean -dfX && ${MODBUS_DIR}/autogen.sh
CONFIGURE_COMMAND ${MODBUS_DIR}/configure --srcdir=${MODBUS_DIR} --prefix=${MODBUS_BIN} --enable-static=yes --disable-shared
BUILD_COMMAND make
INSTALL_COMMAND make install
BUILD_BYPRODUCTS ${MODBUS_STATIC_LIB}
)
add_library(modbus STATIC IMPORTED GLOBAL)
add_dependencies(modbus libmodbus)
set_target_properties(modbus PROPERTIES IMPORTED_LOCATION ${MODBUS_STATIC_LIB})
set_target_properties(modbus PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${MODBUS_INCLUDES})
A component that uses libmodbus can declare its dependency as usual:
add_executable(hello_modbus main.cpp)
target_link_libraries(hello_modbus modbus)
A few notes:
This abuses the DOWNLOAD_COMMAND to perform the autogen.sh step. The git clean -dfX is probably not necessary (it is a leftover from an earlier version that used the BUILD_IN_SOURCE option. If you really want to download the code instead of using a git submodule, you'll need to modify this line appropriately.
We go to the trouble to force a static-only build of the library. Adjust your configure command line if you want shared libraries.
The set_target_properties command to set the IMPORTED_LOCATION will fail without the BUILD_BYPRODUCTS ${MODBUS_STATIC_LIB} declaration.
Likewise, the set_target_properties command to set the INTERFACE_INCLUDE_DIRECTORIES will fail without the file(MAKE_DIRECTORY ${MODBUS_INCLUDES}).
I am using cmake to build my project. For UNIX, I would like to type make from my project's root directory, and have cmake invoked to create the proper Makefiles (if they don't exist yet) and then build my project. I would like the cmake "internal" files (object files, cmake internal Makefiles, etc.) to be hidden (e.g. put in a .build directory) so it doesn't clutter my project directory.
My project has several sub-projects (in particular, a library, a user executable, and a unit test executable). I would like Makefiles (i.e. I type make and this happens) for each sub-project to execute cmake (as above) and build only that sub-project (with dependencies, so the library would be built from the executables' Makefiles, if needed). The resulting binary (.so library or executable) should be in the sub-project's directory.
I made a Makefile which does the main project bit somewhat well, though it feels somewhat hackish. I can't build specific targets using it, because my Makefile simply calls make in cmake's build directory.
Note that because the library is a sole dependency (and probably doesn't need to be build manually, and because I'm lazy) I omitted it in my Makefile.
BUILD_DIR := .build
.PHONY: all clean project-gui ${BUILD_DIR}/Makefile
all: project-gui project-test
clean:
#([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean && rm -r ${BUILD_DIR}) || echo Nothing to clean
project-gui: ${BUILD_DIR}/Makefile
#make -C ${BUILD_DIR} project-gui
#cp ${BUILD_DIR}/project-gui/project-gui $#
project-test: ${BUILD_DIR}/Makefile
#make -C ${BUILD_DIR} project-test
#cp ${BUILD_DIR}/project-test/project-test $#
${BUILD_DIR}/Makefile:
#[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR}
#[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CMAKE_OPTS} ..)
If it helps, here's my project structure (if this is "wrong" please tell me -- I'm still learning cmake):
project/
project/CMakeLists.txt
project/common.cmake
project/Makefile -- see Makefile above for this; should be replaced with something better, building libproject, project-gui, and project-test
project/libproject/
project/libproject/CMakeLists.txt
project/libproject/libproject.so -- after build
project/libproject/Makefile -- doesn't exist yet; should build libproject only
project/libproject/source/
project/libproject/include/
project/project-gui/
project/project-gui/CMakeLists.txt
project/project-gui/Makefile -- doesn't exist yet; should build libproject then project-gui
project/project-gui/source/
project/project-gui/include/
project/project-test/
project/project-test/CMakeLists.txt
project/project-test/Makefile -- doesn't exist yet; should build libproject then project-test
project/project-test/source/
project/project-test/include/
If you haven't caught on yet, I'm basically looking for a way to build the project and sub-projects as if cmake wasn't there: as if my project consisted of only Makefiles. Can this be done? Is the solution elegant, or messy? Should I be trying to do something else instead?
Thanks!
If cmake is generating the makefiles, you can simply include the generated makefile in the master makefile, eg
# makefile
all: # Default
include $GENERATED
$GENERATED:$CMAKEFILE
# Generate the makefile here`
The included files are generated then make is restarted with the new included files. The included files should detail the targets, etc.
You should be able to change the location of used files using the vpath directive, see e.g. the Gnu make manual,
vpath %.o project/.build
else the tedious way is to rewrite the rules making note of the necessary directory.
Ed:
Perhaps we shouldn't use a flat makefile.
Try something like:
# makefile
all: gui test
clean:
$(MAKE) -f $(GUI-MAKE) clean
$(MAKE) -f $(TEST-MAKE) clean
gui:$(GUI-MAKE)
$(MAKE) -f $(GUI-MAKE) all
$(GUI-MAKE):$(GUI-CMAKE)
# Generate
# Same for test
This should work if the $(MAKE) -f $(GUI-MAKE) all command works on the command line, and we've hidden cmake in the generating target. You would have to copy any other targets to the master makefile as well, and take care running make in parallel.
Propagating object files through should involve something like
%.o:$(GUI-MAKE)
$(MAKE) -f $(GUI-MAKE) $#
although you'll probably get errors trying to make test objects