How to run multiple commands with an extra target in QMake - qt

I am making extra targets using qmake, and I'm trying to do two things at the same time: make a new folder, and copy a dll into that folder. Both action separate work fine, but the two together don't work.
something.target = this
# This works:
# something.commands = mkdir newFolder
# This works too (if newFolder exists)
# something.commands = copy /Y someFolder\\file.dll newFolder
# This doesn't work:
something.commands = mkdir newFolder; \
copy /Y someFolder\\file.dll newFolder
QMAKE_EXTRA_TARGETS += something
PRE_TARGETDEPS += this
I thought this was the right syntax (I found similar examples for example here and here), but I am getting the following error:
> mkdir newFolder; copy /Y someFolder\\file.dll newFolder
> The syntax of the command is incorrect.
Is the syntax different on different platforms or something? I'm working on Windows 7, with Qt 5.0.1.

The value of .commands variable is pasted in the place of target commands in Makefile by qmake as is. qmake strips any whitespaces from values and changes them into single spaces so it's impossible to create multiline value without a special tool. And there is the tool: function escape_expand. Try this:
something.commands = mkdir newFolder $$escape_expand(\n\t) copy /Y someFolder\\file.dll newFolder
$$escape_expand(\n\t) adds new line character (ends previous command) and starts next command with a tab character as Makefile syntax dictates.

The and operator also works for me on Linux, and strangely windows.
something.commands = mkdir newFolder && copy /Y someFolder\\file.dll newFolder

You can also append to the .commands variable if you want to avoid backslashes:
target.commands += mkdir toto
target.commands += && copy ...
# Result will be:
target:
mkdir toto && copy ...
Or:
target.commands += mkdir toto;
target.commands += copy ...;
# Result will be:
target:
mkdir toto; copy ...;

Related

qmake INSTALLS for a file not existing yet

Suppose I have a test.pro file with content as followings
unix {
inspro.path = /tmp
inspro.files += test.pro
}
!isEmpty(inspro.path) INSTALLS += inspro
unix {
insdoc.path = /tmp
insdoc.files += test.txt
}
!isEmpty(insdoc.path) INSTALLS += insdoc
Running qmake test.pro results in a Makefile. The file, test.pro, exists already, and the created Makefile contains install_inspro and uninstall_inspro for the file test.pro:
install_inspro: first FORCE
#test -d $(INSTALL_ROOT)/tmp || mkdir -p $(INSTALL_ROOT)/tmp
$(QINSTALL) /home/jianz/test/pro/test.pro $(INSTALL_ROOT)/tmp/test.pro
uninstall_inspro: FORCE
-$(DEL_FILE) -r $(INSTALL_ROOT)/tmp/test.pro
-$(DEL_DIR) $(INSTALL_ROOT)/tmp/
However, corresponding install_insdoc and install_insdoc are created if and only if the file test.txt exists.
In the case that the file test.txt is created as part of QMAKE_POST_LINK, is there a way to force qmake to create install_insdoc and uninstall_insdoc?
I think there's a custom install target CONFIG directive to help with this. Add:
insdoc.CONFIG += no_check_exist
Documented at https://doc.qt.io/qt-5/qmake-variable-reference.html#installs
More details and caveats at https://wiki.qt.io/Undocumented_QMake#Custom_install_config
Related Q/A: qmake copy files created while building

Create dir & Copy files with qmake

I am trying to copy target binary file in multiple folders. In first step I must create those multiple folders. I have followed this example without success.
The only thing that worked was system(mkdir $$OUT_PWD/newFolder), but I'm trying to use
QMAKE_EXTRA_TARGETS for $(MKDIR) followed by $(COPY) from this example.
Using Qt 4.8.6 with qmake 2.01a.
This is how I run qmake:
qmake Server.pro -r -spec linux-g++ CONFIG+=debug CONFIG+=declarative_debug
Update:
This is my current implementation, which creates a list of directories and copies the target binary to selected directories.
# List all server directories
DIRS = server-1 \
server-2 \
server-3 \
server-4
INSTALL_PATH = $$OUT_PWD
# Shadow build detection
!equals(PWD, $$OUT_PWD) INSTALL_PATH = $$replace(INSTALL_PATH, build, install)
# Loop over all given directories and append the 'install' directory to make absolute paths
for(DIR, DIRS) ABS_DIRS += $$INSTALL_PATH/$$DIR
# Create 'copy' commands for $DIRS
for(DIR, ABS_DIRS) CP_CMD += $(COPY) $$OUT_PWD/$$TARGET $$DIR &&
# Ignore last &&
CP_CMD += true
install.commands = $(MKDIR) $$ABS_DIRS && $$CP_CMD
QMAKE_EXTRA_TARGETS += install
QMAKE_POST_LINK += install
The missing part for me was that I didn't execute make with correct arguments. After calling make install which also includes qmake INSTALLS files, the code executes. However this fails on clean build with given error: install: missing file operand. If I rename the install command with for example copy, I get this error: make: copy: Command not found. Any clues?
Got it working. Some side notes ... QtCreator by default creates build-project-kit-debug/release directory for building if shadow build is enabled. This code creates install-project-kit-debug/release directory on same level with listed DIRS as sub directories. Directories are created after compile with create command. Target binary is then copied to DIRS directories after linking.
Thanks to macetw for POST_TARGETDEPS which also lead me to QMAKE_POST_LINK. qmake and make are ran without any extra arguments.
# Sets target destination dir - platform independent
win32 {
build_pass: CONFIG(debug, debug|release) {
DESTDIR = $$OUT_PWD/debug
}
else: build_pass {
DESTDIR = $$OUT_PWD/release
}
}
unix {
DESTDIR = $$OUT_PWD
}
# List all server directories
DIRS = server-1 \
server-2 \
server-3 \
server-4
INSTALL_PATH = $$DESTDIR
# Shadow build detection
!equals(PWD, $$DESTDIR) INSTALL_PATH = $$replace(INSTALL_PATH, build, install)
# Loop over all given directories and append the 'install' directory to make absolute paths
for(DIR, DIRS) ABS_DIRS += $$INSTALL_PATH/$$DIR
# Create 'copy' commands for $DIRS
for(DIR, ABS_DIRS) CP_CMD += $(COPY) $$DESTDIR/$$TARGET $$DIR ;
create.commands = $(MKDIR) $$ABS_DIRS
QMAKE_EXTRA_TARGETS += create
POST_TARGETDEPS += create
QMAKE_POST_LINK += $$CP_CMD
This documentation appears to be missing the use of PRE_TARGETDEPS or POST_TARGETDEPS.
What that means is that the Makefile has the instructions to do what it needs to do, but those targets are not built into the dependency chain, so the Make tool never does them.
If the problem is about doing 2 things (instead of just one), try to put 2 commands in the same line. Like so:
QMAKE_EXTRA_TARGETS += foo
foo.target = $$OUT_PWD/newFolder
foo.commands = $(MKDIR) $$OUT_PWD/newFolder ; $(COPY_DIR) $SOURCE $$OUT_PWD/newFolder
... You might also try "&&" instead of ";", to get strong checks of return codes. You could choose to create 2 QMAKE_EXTRA_TARGETS that depend on one another.
QMAKE_EXTRA_TARGETS += foo bar
foo.target = $$OUT_PWD/newFolder
foo.commands = $(MKDIR) $$OUT_PWD/newFolder
bar.target = $$OUT_PWD/newFolder/file
bar.commands = $(COPY_DIR) $SOURCEOFFILE $$OUT_PWD/newFolder
bar.depends = foo

Change directory in makefile for main shell

I have a following scenario in my build system.
1. 1000 makefiles in src directories
2. There is common.make file being included for all 1000 makefiles
3. links were created for makefiles and sources in object directory from source directory. Hence all makefiles and many more scripts inside makefile are written in such a way as it exists in build directory.
4. obj directory is the dynamic location.
5. Now I removed all links.no more links in object directory.
6. I want to execute all makefiles in source directory where I expect to change the object directory (dynamic directory name) before executing. (I can't use make -C here, because I do not know what directory to change). I can set VPATH for finding sources.
7. I want to make use common.make to change the directory dynamically, but whatever cd, $(shell cd ...) I do in common.make is not reflected in main Makefile.
8. If I do not do this, I will end up in modifying all 1000 makefiles. I do not want to do this.
Please let me know the best of way of doing it. In simple words, I want to change the directory (through common.make) before executing my 1000 makefiles,
I expect common.make to do the following.
1) save srcpath = current path (current path is source directory)
2) Change to output directory (Directory name is dynamic here).
3) set VPATH=srcpath
4) now any makefile in source directory can make use of common.make to compile and have the binaries and objects in output directory.
# This is one of the sample Makefile. I have shortened this file. All makefiles are not using the same names like SRCS, CMDSRCS. It would be different.
# this is existing makefile. Source location /home/user/project/src/mod1/lib/resmgr>make BD=100. I want the output to
# /home/user/project/build/swout100/mod1/lib/resmgr/*. common.make (common make) might validate the argument BD here. BD=101 is not allowed.
# We can force the user to do make -C /home/user/project/build/swout100/mod1/lib/resmgr (no BD validation here. user should know what directory to go).
# I would expect common.make would help the user as utility makefile
TOPDIR = ../../..
MAKEDIR = $(TOPDIR)/make
include $(MAKEDIR)/common.make # It is included in most makefiles. This can be treated as common makefile. I thought of modifying common.make
include ........ #(More includes here)
TARGET = resmgrd
CMDSRCS = resmgr_cli.c \
resmgrlogshow.c \
# more source files here
CMDOBJS = $(CMDSRCS:.c=.o)
CMDHNDLR = resmgrcmd
#... CFLAGS here and library flags here
MDSRC = main.c
SRCS = resmgr.c \
# more source files here
HDRS = resmgr.h
MDOBJ = $(MDSRC:.c=.o)
OBJS = $(SRCS:.c=.o)
$(OBJS) $(MDOBJ) $(CMDOBJS): $(HDRS)
DEPENDSRCS = $(MDSRC) $(SRCS) $(CMDSRCS)
ST_LIBS = $(DEVOSLIBSRC)/apixdr/libapixdr.a
$(TARGET): $(MDOBJ) $(OBJS)
$(CC) $(LDFLAGS) -o $# $^ $(LDLIBS) $(ST_LIBS)
$(CMDHNDLR): $(CMDOBJS)
$(CC) $(LDFLAGS) -o $# $^ $(DEVOSLIBS) $(IPCLIB) $(KILIB) $(MIAUXLIB) \
$(RESMGRLIB) $(RBACLIB)
install:: install-server
install-server: $(TARGET) $(TARGET).options $(DEVOSSBINDIR) $(DEVOSCONFDIR)
$(INSTALL) -m 755 $(TARGET) $(DEVOSSBINDIR)
install-commands: $(DEVOSBINDIR)/$(CMDHNDLR) \
install-admin-cmds install-user-cmds
clean::
$(RM) $(OBJS) $(TARGET) $(SCRIPTS) $(RAWMAN) $(CMDHNDLR) $(ZIPMAN)
I found an answer to my question.
http://make.paulandlesley.org/multi-arch.html

Running a program/script from QMake

We have a fairly large code-base. The vast majority of the code is compiled using qmake to produce the makefiles. However, there are some sub-projects that get produced by running batch files or running other programs.
I'd like to be able to have everything compiled using qmake, but I can't figure out how to get qmake to simply run a script.
One thing that I've tried is using QMAKE_EXTRA_TARGETS in my pro file, like so:
TEMPLATE = lib
SOURCES = placeholder.cpp
CONFIG += no_link staticlib
batch_runner.target = placeholder.cpp
batch_runner.commands = my_batch_file.bat
QMAKE_EXTRA_TARGETS = batch_runner
I then have to have the batch file produce placeholder.cpp like so:
# do the real work here
# ...
# create placeholder.cpp so qmake and nmake are happy
echo // dummy >> placeholder.cpp
This seems to work fine. The trouble is that it is somewhat hokey. If I don't specify batch_runner.target (i.e. I leave it blank) or don't put placeholder.cpp in SOURCES then the batch file never gets run. This is because qmake isn't making batch_runner.commands the action for any other dependency in the Makefile.
Is there any better way to get QMake to construct a Makefile such that a script is run when the Makefile executes?
It looks like QMAKE_POST_LINK works well for this sort of thing.
This seems to get the job done. my_batch_file.bat runs when nmake runs (rather than when qmake runs) and I don't need to do anything funny with placeholder targets or files.
It's quite likely that I don't need all of the items listed in 'CONFIG'.
TEMPLATE = lib
TARGET =
CONFIG += no_link target_predeps staticlib
QMAKE_POST_LINK = my_batch_file.bat
QMAKE_CLEAN += batch_output.obj
Try the system() command. For example:
system(pwd)
Here is another solution:
TEMPLATE = aux
OBJECTS_DIR = ./
DESTDIR = ./
first.commands = my_batch_file.bat
QMAKE_EXTRA_TARGETS += first
QMAKE_CLEAN += batch_output.obj
The template aux basically produces a makefile which does nothing when run without specifying a target. The OBJECTS_DIR and DESTDIR variables are set to the current directory to prevent that qmake creates the debug and release directories (it's important to set them to ./ and not just to .; at least on Windows). Then, using QMAKE_EXTRA_TARGETS, we redefine the target first to run the custom command when the makefile is invoked without target.
It's a bit hacky but it gets the job done.
Addition:
If you want to prevent the generation of three makefiles (Makefile, Makefile.Debug, Makefile.Release), you can add
CONFIG -= debug_and_release
However, if you use this and depending on how the makefile is invoked (always invoked manually, invoked by parent directory's "subdirs" *.pro file, ...), it might be necessary to create fake debug and release targets to avoid "no rule to make target..." errors. For example:
release.target = release
release-clean.target = release-clean
release-install.target = release-install
[...]
debug.target = debug
debug-clean.target = debug-clean
debug-install.target = debug-install
[...]
QMAKE_EXTRA_TARGETS += release release-clean release-install [...]
QMAKE_EXTRA_TARGETS += debug debug-clean debug-install [...]
You could use the SUBDIRS configuration to run multiple different targets, even from the same makefile. This might work especially well with your extra targets, as a subdir configuration can specific a specific target in the makefile to run (see undocumented qmake for details). In this case, I would put all of the "regular" build commands in one .pro file, the external build commands in another, and a subdirs .pro file to build all of them. I haven't tested anything quite like this, but it should work.
regular.pro:
SOURCES += main.cpp
TARGET = regular.exe
external.pro:
batch_runner.commands = my_batch_file.bat
QMAKE_EXTRA_TARGETS += batch_runner
other_runner.commands = other_batch_file.bat
QMAKE_EXTRA_TARGETS += other_runner
do_it_all.pro:
TEMPLATE = subdirs
CONFIG += ordered
regular.file = regular.pro
SUBDIRS += regular
batch.file = external.pro
batch.target = batch_runner
SUBDIRS += batch
other.file = external.pro
other.target = other_runner
SUBDIRS += other

how to export headers using Qt pro files

I've a project with following files
TestProject/api/apiheader1.h
TestProject/api/apiheader2.h
TestProject/src/apiimplementaton.cpp
TestProject/inc/apiimplementation.h
TestProject/TestProject.pro
When the project TestProject.pro is built headers apiheader1.h, apiheader2.h needs to be copied to /usr/include/TestLib/. Is it possible to do this by specifying it in project file TestProject.pro.?
Any pointers / links will be helpful.
You can add this to the pro file... in qmake you can add extra targets...The copyheaders will get run once the target is built..
QMAKE_EXTRA_TARGETS += copyheaders
POST_TARGETDEPS += copyheaders
copyheaders.commands += mkdir -p /usr/include/TestlLib
copyheaders.commands += cp -f PATH_TO_HEADERS/apiheader1.h /usr/include/TestLib
copyheaders.commands += cp -f PATH_TO_HEADERS/apiheader2.h /usr/include/TestLib
Are you sure that you want to move the files? Moving source files around feels wrong.
As for doing it using qmake, you can use the system() function to simply cp the files in question. http://pepper.troll.no/s60prereleases/doc/qmake-function-reference.html#system-command

Resources