Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a qmake function that creates a custom make target?

I know that we have QMAKE_EXTRA_TARGETS to create new makefile targets, that is used as follows (as seen in http://blog.qt.io/blog/2008/04/16/the-power-of-qmake/):

conv.target=convert
conv.input=file.in
conv.output=file.out
conv.commands=convert.sh file.in file.out
QMAKE_EXTRA_TARGETS+=conv

In my case, convert.sh is used for multiple files and targets. I would like to create a method with arguments (target_name, input_file, output_file), that creates the task for me, so that I don't have to repeat the above lines.

The documentation on qmake is quite lacking, or I haven't found the correct source, but to my understanding, there are two types of functions in qmake: replace and test (http://doc.qt.io/qt-5/qmake-language.html#replace-functions) and we can create custom ones using defineReplace and defineTest.

I have tried:

defineTest(createConvertTask) {
    custom.target = $$1
    custom.input = $$2
    custom.output = $$3
    custom.commands = convert.sh $$2 > $$3
    QMAKE_EXTRA_TARGETS += custom
}

but that doesn't really work, as after calling createConvertTask multiple times, QMAKE_EXTRA_TARGETS will just contain multiple copies of the string custom.

However, this

defineTest(createConvertTask) {
    $$1.target = $$1
    $$1.input = $$2
    $$1.output = $$3
    $$1.commands = convert.sh $$2 > $$3
    QMAKE_EXTRA_TARGETS += $$1
}

fails with error example.pro:2: error: Left hand side of assignment must expand to exactly one word.

Any ideas on how to approach this?

like image 966
majk Avatar asked Jun 03 '16 12:06

majk


1 Answers

1.Option: custom compiler

Use a custom compiler like this:

convert.input = LIST_OF_IN_FILES  # note: no $$
convert.output = $${SOME_DIR}/${QMAKE_FILE_BASE}.ext
convert.commands = convert.sh ${QMAKE_FILE_IN} > $${SOME_DIR}/${QMAKE_FILE_BASE}.ext

convert.CONFIG += no_link target_predeps
QMAKE_EXTRA_COMPILERS += convert

The variables ${QMAKE_FILE_IN} contains the current input file, same as ${QMAKE_FILE_BASE} but without extension. Here, the output filenames are generated out of the input files. The CONFIG options tell qmake not to add the output files to the objects list and to add them as prerequisites of the main target. Additionally a make target compiler_convert_make_all will be generated.

Just add files:

LIST_OF_IN_FILES += file1 file2

and make

make compiler_convert_make_all

This option also adds all output files to the clean target (will be deleted on make clean.

2.Option: use eval() and export()

To use variables as left hand expression you can use the eval() function, that 'Evaluates the contents of the string using qmake syntax rules'.

eval($${1}.target = $$1)

Since this is done inside a function you need to export() all variables to the global scope.

eval(export($${1}.target))

Afterwards add target and export QMAKE_EXTRA_TARGETS as well:

QMAKE_EXTRA_TARGETS += $${1}
export(QMAKE_EXTRA_TARGETS)

Complete with a replace function, the return value will be added to the dependencies of the custom convert target:

convert.target = convert

defineReplace(createConvertTask) {
    eval($${2}_custom.target = $$2)
    eval($${2}_custom.depends = $$1)
    eval($${2}_custom.commands = convert.sh $$1 > $$2)
    eval(export($${2}_custom.target))
    eval(export($${2}_custom.depends))
    eval(export($${2}_custom.commands))

    QMAKE_EXTRA_TARGETS += $${2}_custom
    export(QMAKE_EXTRA_TARGETS)
    return($${2}_custom)
 }

 convert.depends += $$createConvertTask(in_file_1, out_file_1)
 convert.depends += $$createConvertTask(in_file_2, out_file_2)

 QMAKE_EXTRA_TARGETS += convert

The results in the generated Makefile:

out_file_1: in_file_1
       convert.sh in_file_1 > out_file_1

out_file_2: in_file_2
       convert.sh in_file_2 > out_file_2

convert: out_file_1 out_file_2

This approach is more flexible and can be extended to support the a variable target parameter (here constant convert).

like image 93
LeBlue Avatar answered Oct 24 '22 05:10

LeBlue