Discussion:
[cmake-developers] Current deficiencies of automoc
Alan W. Irwin
2016-10-20 18:30:58 UTC
Permalink
This is a follow up to the CMake mailing list thread with the subject line
"Cannot get automoc to work properly with recommended Qt5 support
method".

The deficiency I found with automoc is (as far as I can tell) it does
not properly handle the case where the header that should be processed
by moc is located in a different source-tree directory than the source
file that includes that header. For PLplot I have worked around this
deficiency by abandoning use of automoc altogether and instead used
custom targets that invoked qt5_wrap_cpp. But the whole concept of
automoc is far superior to a custom target approach so this is a plea
to the CMake developers to fix the above deficiency in automoc.

To be specific here is the way I believe automoc should work. If

#include "moc_<name>.cpp"

is found in a source file under automoc
control, then if moc_<name>.cpp could not be found in any of the
include directories for the target, then search those include
directories (including source-tree equivalents of build-tree include
directories) for <name>.h, run moc on that file and place the result
moc_<name>.cpp in the build directory corresponding to <name.h>.

So the result is moc would be run just once on the correct header file
with the moc_<name>.cpp result stored in one logical location no
matter how many different source files in different directories have
code with the above #include.

My experiments showed that automoc currently falls short of this
behaviour and only works if <name>.h is in the current source
directory and I consider this deficiency to be a serious bug in
automoc. Furthermore, the documentation of automoc needs improving to
explicitly name the header file being processed by moc when
encountering the above #include. Furthermore, the directories
searched for that header file should be stated. For the current buggy
state of automoc that would just be the current source tree, but once
the bug was fixed it would be everything mentioned in
include_directories and their source-tree equivalents.

I hate to lose issues that can be trivially fixed on bug trackers, but
if the above automoc fix and automoc documentation fix are not
trivial, then I would be willing to incorporate the above and any
further discussion here into an official CMake bug report.

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers
Brad King
2016-10-20 19:08:24 UTC
Permalink
Post by Alan W. Irwin
The deficiency I found with automoc is (as far as I can tell) it does
not properly handle the case where the header that should be processed
by moc is located in a different source-tree directory than the source
file that includes that header.
[snip]
Post by Alan W. Irwin
To be specific here is the way I believe automoc should work. If
#include "moc_<name>.cpp"
is found in a source file under automoc
control, then if moc_<name>.cpp could not be found in any of the
include directories for the target, then search those include
directories (including source-tree equivalents of build-tree include
directories) for <name>.h, run moc on that file and place the result
moc_<name>.cpp in the build directory corresponding to <name.h>.
[snip]
Post by Alan W. Irwin
this is a plea to the CMake developers to fix the above deficiency
Adding to Cc some folks that may have worked on automoc features
in the past. I have little understanding of the feature myself.
Unless someone steps forward to implement this it is unlikely to
be fixed.
Post by Alan W. Irwin
I hate to lose issues that can be trivially fixed on bug trackers, but
if the above automoc fix and automoc documentation fix are not
trivial, then I would be willing to incorporate the above and any
further discussion here into an official CMake bug report.
Please construct a minimal/complete example source tree/tarball
that demonstrate the layout you'd like to have work. That will
be helpful in constructing such a bug report.

-Brad
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers
Tobias Hunger
2016-10-20 19:17:30 UTC
Permalink
Hi!
Post by Brad King
Post by Alan W. Irwin
To be specific here is the way I believe automoc should work. If
#include "moc_<name>.cpp"
is found in a source file under automoc
control, then if moc_<name>.cpp could not be found in any of the
include directories for the target, then search those include
directories (including source-tree equivalents of build-tree include
directories) for <name>.h, run moc on that file and place the result
moc_<name>.cpp in the build directory corresponding to <name.h>.
[snip]
Post by Alan W. Irwin
this is a plea to the CMake developers to fix the above deficiency
If you include moc_name.cpp, then you need to run moc on this *source*
file. That is what allows you to have private classes in your source file
that derive from QObject.

The headers should be covered by automoc automatically: Any header
containing a Q_OBJECT macro should be moc-ed. So there should not be any
need to include moc_*.cpp files in source files for any header.

At least that is how I always use this with qmake, but I am hardly an
expert on how moc should work:-)

Best Regards,
Tobias
Alan W. Irwin
2016-10-20 19:49:16 UTC
Permalink
Disclaimer:

I am no expert on any of this stuff so the conclusions I have drawn
are based on the particular experiments I have done and are probably
limited because of that.
Post by Tobias Hunger
Hi!
Post by Brad King
Post by Alan W. Irwin
To be specific here is the way I believe automoc should work. If
#include "moc_<name>.cpp"
is found in a source file under automoc
control, then if moc_<name>.cpp could not be found in any of the
include directories for the target, then search those include
directories (including source-tree equivalents of build-tree include
directories) for <name>.h, run moc on that file and place the result
moc_<name>.cpp in the build directory corresponding to <name.h>.
[snip]
Post by Alan W. Irwin
this is a plea to the CMake developers to fix the above deficiency
If you include moc_name.cpp, then you need to run moc on this *source*
file. That is what allows you to have private classes in your source file
that derive from QObject.
That is not the case I am concerned with which is the source file has
no direct reference to the Q_OBJECT macro. Instead it #includes a
header that uses that macro. My experiments (see disclaimer above)
with that case show moc needs to be run directly on the header, and
the resulting generated file needs to be #included in the source file.
Post by Tobias Hunger
The headers should be covered by automoc automatically: Any header
containing a Q_OBJECT macro should be moc-ed. So there should not be any
need to include moc_*.cpp files in source files for any header.
Actually my experiments show the headers using the Q_OBJECT macro are
completely ignored by automoc unless you specifically put

#include moc_<name>.cpp

in the source file, and that works only if <name>.h is in the current
directory. And I want to see that severe current directory limitation
removed as above.
Post by Tobias Hunger
At least that is how I always use this with qmake, but I am hardly an
expert on how moc should work:-)
That lack of expertise goes double for me. :-) See disclaimer above.

Alan

__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers
Alan W. Irwin
2016-10-20 20:24:27 UTC
Permalink
Post by Brad King
Please construct a minimal/complete example source tree/tarball
that demonstrate the layout you'd like to have work. That will
be helpful in constructing such a bug report.
A minimal example illustrating the issue is a great idea. However,
the problem is I am not much of an expert on C++ or Qt5 so reducing
the PLplot Qt5 example source code to such a minimal example is going
to be somewhat time consuming for me. So unless someone here lends me
a hand by implementing the needed simple Qt5 source code, I first plan
to look through the many Qt5 demos accessible on the web to see if any
of them qualify in terms of no Q_OBJECT in source, but Q_OBJECT in
#included header, and as a last resort I will attempt to simplify the
PLplot Qt5 example source code. Then follow up with implementing the
CMake aspects of that simple example which should be trivial for me.

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers
Alan W. Irwin
2016-10-20 23:29:39 UTC
Permalink
Post by Brad King
Please construct a minimal/complete example source tree/tarball
that demonstrate the layout you'd like to have work. That will
be helpful in constructing such a bug report.
OK. I have attached the requested minimal example to serve as the
basis for further discussion. The files in the tarball are

test_qt5/
test_qt5/include/
test_qt5/include/test_q_object.h
test_qt5/main.cpp
test_qt5/CMakeLists.txt

include/test_q_object.h is a header that contains a minimal use of
Q_OBJECT. (Likely too minimal so I will need help with that see below.)
main.cpp is a "hello-world" example that #includes that header. It also #includes
the moc-generated moc_test_q_object.cpp.

The USE_AUTOMOC option for this test project defaults to OFF. In that
default case this test project is set up so that the qt5_wrap_cpp is called instead of using automoc, and the
result is the compilation works fine (all headers and files generated
by moc are found with no issues) but there is a link error

CMakeFiles/helloworld.dir/main.cpp.o:(.data.rel.ro._ZTV7MyClass[_ZTV7MyClass]+0x28):
undefined reference to MyClass::~MyClass()'

which likely has to do with include/test_q_object.h being too minimal.
I would appreciate help with that issue to complete this example, but
that is a side issue and the principal result is the compile (as
opposed to the link) was a success with the default -DUSE_AUTOMOC=OFF.

However, if you try -DUSE_AUTOMOC=ON with this project the compile
step (before it even gets to the link step) fails as follows:

Automatic moc for target helloworld
/home/software/cmake/install-3.5.2/bin/cmake -E cmake_autogen /home/software/plplot/HEAD/test_qt5/build_dir/CMakeFiles/helloworld_automoc.dir/ ""
AUTOGEN: Checking /home/software/plplot/HEAD/test_qt5/main.cpp
AUTOGEN: error: /home/software/plplot/HEAD/test_qt5/main.cpp The file includes the moc file "moc_test_q_object.cpp", but could not find header "test_q_object{.h,.hh,.h++,.hm,.hpp,.hxx,.in,.txx}" in /home/software/plplot/HEAD/test_qt5/

I hope a simple solution to this deficiency of the current automoc can
be found using the following ideas (copied from my previous post to
keep this self-contained).

If

#include "moc_<name>.cpp"

is found in a source file under automoc
control, then if moc_<name>.cpp could not be found in any of the
include directories for the target, then search those include
directories (including source-tree equivalents of build-tree include
directories) for <name>.h, run moc on that file and place the result
moc_<name>.cpp in the build directory corresponding to <name.h>.

So the result is moc would be run just once on the correct header file
with the moc_<name>.cpp result stored in one logical location no
matter how many different source files in different directories have
code with the above #include.

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
Sebastian Holtermann
2016-10-21 08:10:27 UTC
Permalink
Post by Alan W. Irwin
Post by Brad King
Please construct a minimal/complete example source tree/tarball
that demonstrate the layout you'd like to have work. That will
be helpful in constructing such a bug report.
OK. I have attached the requested minimal example to serve as the
basis for further discussion. The files in the tarball are
test_qt5/
test_qt5/include/
test_qt5/include/test_q_object.h
test_qt5/main.cpp
test_qt5/CMakeLists.txt
include/test_q_object.h is a header that contains a minimal use of
Q_OBJECT. (Likely too minimal so I will need help with that see below.)
main.cpp is a "hello-world" example that #includes that header. It also #includes
the moc-generated moc_test_q_object.cpp.
The USE_AUTOMOC option for this test project defaults to OFF. In that
default case this test project is set up so that the qt5_wrap_cpp is
called instead of using automoc, and the
result is the compilation works fine (all headers and files generated
by moc are found with no issues) but there is a link error
undefined reference to MyClass::~MyClass()'
which likely has to do with include/test_q_object.h being too minimal.
I would appreciate help with that issue to complete this example, but
that is a side issue and the principal result is the compile (as
opposed to the link) was a success with the default -DUSE_AUTOMOC=OFF.
However, if you try -DUSE_AUTOMOC=ON with this project the compile
Automatic moc for target helloworld
/home/software/cmake/install-3.5.2/bin/cmake -E cmake_autogen
/home/software/plplot/HEAD/test_qt5/build_dir/CMakeFiles/helloworld_automoc.dir/
""
AUTOGEN: Checking /home/software/plplot/HEAD/test_qt5/main.cpp
AUTOGEN: error: /home/software/plplot/HEAD/test_qt5/main.cpp The file
includes the moc file "moc_test_q_object.cpp", but could not find header
"test_q_object{.h,.hh,.h++,.hm,.hpp,.hxx,.in,.txx}" in
/home/software/plplot/HEAD/test_qt5/
I hope a simple solution to this deficiency of the current automoc can
be found using the following ideas (copied from my previous post to
keep this self-contained).
If
#include "moc_<name>.cpp"
is found in a source file under automoc
control, then if moc_<name>.cpp could not be found in any of the
include directories for the target, then search those include
directories (including source-tree equivalents of build-tree include
directories) for <name>.h, run moc on that file and place the result
moc_<name>.cpp in the build directory corresponding to <name.h>.
So the result is moc would be run just once on the correct header file
with the moc_<name>.cpp result stored in one logical location no
matter how many different source files in different directories have
code with the above #include.
Alan
__________________________
Alan W. Irwin
Hi!

I tried your example.
It isn't complete, test_q_object.h needs an
#include <QObject>
and a constructor/destructor definition, e.g.:
MyClass(QObject *parent = 0) {;}
~MyClass(){;}

With regards to automoc the
#include "moc_test_q_object.cpp"
in the end should not be neccessary since
#include "test_q_object.h"
already references to the header.
The problem is that this reference is not a direct path from the
source file but relies on include_directories.
CMake does not seem to populate automoc's scan list with files
from include_directories.
I tried to figure out why but this is quite complex.

A quick fix for the example would be to explicitly add the
headers-to-moc to the sources list.
- add_executable(helloworld main.cpp)
+ add_executable(helloworld main.cpp
+ ${CMAKE_SOURCE_DIR}/include/test_q_object.h)

The #include "moc_test_q_object.cpp" in main.cpp can be removed then.

-Sebastian
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers
Jean-Michaël Celerier
2016-10-21 09:02:51 UTC
Permalink
Post by Sebastian Holtermann
A quick fix for the example would be to explicitly add the
headers-to-moc to the sources list.
This has the nice side-effect of making your project much easier to use in
IDEs.
Alan W. Irwin
2016-10-21 11:39:00 UTC
Permalink
On 2016-10-21 09:42+0200 Sebastian Holtermann wrote:

[...]
Post by Sebastian Holtermann
Hi!
I tried your example.
It isn't complete, test_q_object.h needs an
#include <QObject>
MyClass(QObject *parent = 0) {;}
~MyClass(){;}
Hi Sebastian:

Thanks for that fix which indeed solves the linking issue.
Post by Sebastian Holtermann
With regards to automoc the
#include "moc_test_q_object.cpp"
in the end should not be neccessary since
#include "test_q_object.h"
already references to the header.
The problem is that this reference is not a direct path from the
source file but relies on include_directories.
CMake does not seem to populate automoc's scan list with files
from include_directories.
I tried to figure out why but this is quite complex.
I hope you are able to fix this along the lines I have mentioned
(which includes putting all generated results in the build tree
corresponding to the header) since using #include
"moc_test_q_object.cpp" in main.cpp is currently the only documented
way to use automoc (see, e.g.,
<https://cmake.org/cmake/help/v3.6/prop_tgt/AUTOMOC.html>).
Post by Sebastian Holtermann
A quick fix for the example would be to explicitly add the
headers-to-moc to the sources list.
- add_executable(helloworld main.cpp)
+ add_executable(helloworld main.cpp
+ ${CMAKE_SOURCE_DIR}/include/test_q_object.h)
The #include "moc_test_q_object.cpp" in main.cpp can be removed then.
That idea (specifying the fullpath of the original header as part of the source code)
does indeed make automoc work properly. "ldd -r helloworld" shows
no linking issues, I can run the executable without issues,
and "nm --defined-only --demangle helloworld |less" shows lots
of references to MyClass. I attach a revised tarball
example with the test_q_object.h fix and this
change.

However, there are still two problems with this method which
I will call the fullpath method to distinguish it from the documented
#include method.

1. The automoc documentation at
<https://cmake.org/cmake/help/v3.6/prop_tgt/AUTOMOC.html> only
documents the #include method (which doesn't work for the current test
case nor for PLplot), and the above working fullpath method is not
documented at all there.

2. With that fullpath method, The automoc-generated
helloworld_automoc.cpp and moc_test_q_object.cpp are located in
${CMAKE_CURRENT_BINARY_DIR} (the build directory where the helloworld
executable is located), and that is not ideal. For example, I have no
idea how the compile process found that directory to include those
files since that directory is specifically not mentioned in
include_directories for this project. It also means that for
executables and libraries in a variety of directories that include
${CMAKE_SOURCE_DIR}/include/test_q_object.h in their source list will
be generating duplicate moc_test_q_object.cpp in a variety of
different directories.

Thus, it seems to me the more logical location for these two
automoc-generated files would be ${CMAKE_BINARY_DIR}/include. Note
that ${CMAKE_BINARY_DIR}/include/helloworld_automoc.cpp is unique
(because the target name helloworld must be unique), and
${CMAKE_BINARY_DIR}/include/moc_test_q_object.cpp is also unique
because it corresponds to the unique filename
${CMAKE_SOURCE_DIR}/include/test_q_object.h. So this means there is
no chance of nameclashes with this location (although to be fair that
is also true of the current location for these two generated files).
This suggested location is also the one I suggest for the #include
method, and that consistency of location between the two methods
(and also the qt5_wrap_cpp method) is important.

Of course, if ${CMAKE_SOURCE_DIR}/include/test_q_object.h appears in
source lists for lots of different executables and libraries, automoc
has to test whether ${CMAKE_BINARY_DIR}/include/moc_test_q_object.cpp
has already been generated so that generation is only done once. I
presume such a check would be easy to implement if automoc doesn't do
that already.

In sum, I hope you are willing to fix the currently documented automoc
"#include" method so it puts all generated results in the build tree
corresponding to the header, update the automoc documentation so you
also mention the "fullpath" alternative, and also similarly fix that
method so the location of the two generated files is in the build
directory corresponding to the header rather than the build directory
corresponding to the source file.

My apologies for making suggestions for improvement without being able
to help you with the implementation (except testing of results), but
my C++ skills and CMake developer skills are just not up to it (as you
could probably tell from the required test_q_object.h fix you had to
suggest.)

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
Nagger
2016-10-21 23:01:03 UTC
Permalink
Post by Alan W. Irwin
Post by Sebastian Holtermann
headers-to-moc to the sources list.
- add_executable(helloworld main.cpp)
+ add_executable(helloworld main.cpp
+ ${CMAKE_SOURCE_DIR}/include/test_q_object.h)
The #include "moc_test_q_object.cpp" in main.cpp can be removed then.
1. The automoc documentation at
<https://cmake.org/cmake/help/v3.6/prop_tgt/AUTOMOC.html> only
documents the #include method (which doesn't work for the current test
case nor for PLplot), and the above working fullpath method is not
documented at all there.
At least in cmake-qt(7) [1] this is documented:

If a |Q_OBJECT| or |Q_GADGET| macro is found in a header file, |moc|
will be run on the file. The result will be put into a file named
according to |moc_<basename>.cpp|. If the macro is found in a C++
implementation file, the moc output will be put into a file named
according to |<basename>.moc|, following the Qt conventions. The |moc
file| may be included by the user in the C++ implementation file with a
preprocessor |#include|. If it is not so included, it will be added to a
separate file which is compiled into the target.


Marc


[1] https://cmake.org/cmake/help/v3.6/manual/cmake-qt.7.html#automoc
Alan W. Irwin
2016-10-22 01:01:03 UTC
Permalink
Post by Alan W. Irwin
1. The automoc documentation at
<https://cmake.org/cmake/help/v3.6/prop_tgt/AUTOMOC.html> only
documents the #include method (which doesn't work for the current test
case nor for PLplot), and the above working fullpath method is not
documented at all there.
If a |Q_OBJECT| or |Q_GADGET| macro is found in a header file, |moc| will be
run on the file. The result will be put into a file named according to
|moc_<basename>.cpp|. If the macro is found in a C++ implementation file, the
moc output will be put into a file named according to |<basename>.moc|,
following the Qt conventions. The |moc file| may be included by the user in
the C++ implementation file with a preprocessor |#include|. If it is not so
included, it will be added to a separate file which is compiled into the
target.
Hi Marc:

I have put my response to your comment back on the list where I think it
belongs.

I don't agree with your above conclusion. The above remarks immediately refer to
header files and imply automoc scans them to find the ones that contain
the Q_OBJECT macro and certainly does not imply the user must list
the files to be scanned directly as fullpaths in the add_executable
(or add_library) command. And the last sentence implies that
if the so-called #include method is not used, then automoc will figure
everything out for itself, i.e., the fullpath method allowing the
user to specify which headers are scanned by moc is not documented
here at all.

If the first sentence in the above paragraph had referred to header
files appearing in the list of source files for add_executable or
add_library and/or if the last sentence in the above paragraph had
been replaced by

"If it is not so included, the user must put the fullpaths of the
headers that need moc processing in the source list for add_executable
or add_library." then I would agree with your conclusion, but that
type of specific documentation of the fullpath method is just not
currently in the cmake-qt documentation.

By the way, I have been able to show that the "leaving it completely
to automoc" method documented above does not work with the second
(fixed) version of my simple example, and I urge you to try that
experiment also by making the following additional change (from
"fullpath" to "leave it to automoc")

- add_executable(helloworld main.cpp ${CMAKE_SOURCE_DIR}/include/test_q_object.h)
+ add_executable(helloworld main.cpp)

For this case nm shows everything in test_q_object.h is completely ignored
by automoc despite the '#include "test_q_object.h"' in main.cpp.

N.B. the above documentation is likely correct and the "leave it to
automoc" method should work but it doesn't for this simple example, and that is likely
due to the same bug that keeps the "#include" method from working for
this simple example of an include file in a separate directory.

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers
Sascha Cunz
2016-10-22 02:35:45 UTC
Permalink
Hi Alan,
Post by Alan W. Irwin

I don't agree with your above conclusion. The above remarks immediately refer to
header files and imply automoc scans them
Which it does :)
Post by Alan W. Irwin
to find the ones that contain the Q_OBJECT macro and
and/or Q_GADGET.
Post by Alan W. Irwin
certainly does not imply the user must list the files to be scanned directly
Right. And it’s not required most of the time.
But automoc must know where to look for. It can only do that if something tells it where to look - If your header files are in the same directory as the source files, they’re getting added and scanned automatically (Not related to automoc, actually). See the minimum example below.

If, like in your example, the files are in different directories, you have to add them to add_executable / add_library in order to let automoc know that it shall scan them.
Post by Alan W. Irwin
as fullpaths in the add_executable (or add_library) command.
The full path requirement here is a false perception. It will certainly do no harm to be explicit with the parameters to add_executable/add_library, but the default is to search relative to ${CMAKE_CURRENT_SOURCE_DIR}.

And as mentioned by others in the thread, it’s a good idea to explicitly list your header files. As this will improve how certain IDEs show your project.

The above _is_ actually the default behaviour that suites 95% of the cases where moc needs to be run. For the other cases, where Q_OBJECT / Q_GADGET is used inside a .cpp file, there is the option to #include a file following the pattern “moc_%s.cpp” where %s is the name of the containing C++ source file without extension.
Post by Alan W. Irwin
And the last sentence implies that if the so-called #include method is not used, then
automoc will figure everything out for itself, i.e., the fullpath method allowing the
user to specify which headers are scanned by moc is not documented here at all.
From cmake-qt[7]:

The AUTOMOC target property controls whether cmake(1)
inspects the C++ files in the target
to determine if they require moc to be run.

I clearly states that it will scan the files added to the target.

However, I see that the take away from the thread should probably be that the wording in the documentation could be improved. To be fair, it is in general very hard for someone who knows a tool and it’s complete history to write documentation that someone who doesn’t have that prior knowledge is able to understand. So, improving things here usually relies on input like yours to figure out what actually has to be improved.
I could imagine that in this case, the term “C++ files” didn’t trigger an association to header files.

Cheers,
Sascha

P.S.: Since both Qt4 and Qt5 integrations of Qt nowadays use generator expressions, in my experience it’s close to impossible to accurately mimic automoc behaviour inside CMakeLists.txt. This is though required in one specific scenario, but I don’t think this can be fixed unless automoc would be rewritten from scratch (If target T has a custom rule that creates a header file, which turns out to be run through moc - automoc, which is a separate target that T depends on, can impossibly scan the file that [through target-dependency] will be generated _after_ the automoc target is built).

Minimal working example:

$ tail -n50 CMakeLists.txt t.cpp t.hpp
==> CMakeLists.txt <==
cmake_minimum_required(VERSION 3.6)
project(X)
set(CMAKE_AUTOMOC TRUE)
find_package(Qt5Core)
add_executable(a t.cpp)
target_link_libraries(a Qt5::Core)

==> t.cpp <==
#include "t.hpp"
int main(int,char**)
{ X x; return 0; }

==> t.hpp <==
#include <QObject>
struct X: public QObject{
X() = default;
Q_OBJECT
};
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cma
Alan W. Irwin
2016-10-22 04:44:29 UTC
Permalink
Post by Sascha Cunz
But automoc must know where to look for. It can only do that if
something tells it where to look - If your header files are in the
same directory as the source files, they’re getting added and scanned
automatically.
Post by Sascha Cunz
If, like in your example, the files are in different directories,
you have to add them to add_executable / add_library in order to let
automoc know that it shall scan them.

That is a good summary of what I have discovered through
experimentation. However, I view these results for the separate
header file directory as an unexpected constraint of automoc at best.
Compilers know exactly where the header files are through
include_directories or the equivalent target PROPERTY so why can't
automoc find those same header files using similar logic?

Of course, I am in the odd position (as I explained before) of not
being able to help out with implementing such logic so if it turns
out nobody wants to clean up this issue at the moment, I will put
it on the bugtracker for future reference.

[...]
Post by Sascha Cunz
However, I see that the take away from the thread should probably be
that the wording in the documentation could be improved. To be fair,
it is in general very hard for someone who knows a tool and it’s
complete history to write documentation that someone who doesn’t have
that prior knowledge is able to understand. So, improving things here
usually relies on input like yours to figure out what actually has to
be improved.

I agree. I have already suggested some possible changes to the
documentation on the initial thread on the CMake mailing list and this
additional thread here on the CMake developer list. But if nobody is
inspired to take immediate action on fixing the problem summarized
above (which would largely make the current documentation correct), I will write
up these documentation issues for the current automoc behaviour for
the bugtracker as well.

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http:/
Sascha Cunz
2016-10-22 06:44:32 UTC
Permalink
Post by Alan W. Irwin
Compilers know exactly where the header files are through
include_directories or the equivalent target PROPERTY so why can't
automoc find those same header files using similar logic?
In short: Because you really do not want automoc to do that.

A bit longer; highlighting the semantic problem:

The following applies to targets that you define as well as the external ones. The external one that you certainly can’t skip is QtCore, so I’ll explain it in terms of Qt5::Core.

By adding Qt5::Core to your target’s dependencies at least one -I option is added to the compiler, so it knows where to find Qt5 Core’s header files. At the same time you might have a subdirectory in your source tree that contains some of your header files that you also want to be searched, so you add i.e. “target_include_directories(MyTgt ${PROJECT_SOURCE_DIR}/FooModule)”. Now, the list of include directories for MyTgt contains two entries: Qt5::Core’s headers and FooModule. They are not distinguishable by any means. The question now is: How should automoc know which files you want to run through moc and which files not?

There are actually 3+1 scenarios now:

1. qcoreapplication.h - If you run automoc on that file, your target ends up defining the meta data for QCoreApplication, which is inefficient and will either lead to undefined behaviour or on most platforms to linker errors.
Independent of the technical things below, the decision to run or not run such headers through moc seems to be impossible to automate - One would need to either white or black list the directories used / not used for automoc.

2. FooModule/file1.h, which is included from file1.cpp in MyTgt - You might want to run that through moc, but actually only in the case that the compiler is building MyTgt. If the compiler is building another one of your targets that happens to require this include path, you end up the same as in case 1 above.

3. FooModule/file2.h, which does not have a corresponding .cpp file in MyTgt - (if this was on the system level: for example, not all files in /usr/include belong to the same project) This will lead to unresolved symbols in MyTgt (on most platforms) and the inability to actually execute MyTgt, unless it is linked against the library that actually contains the .cpp file (on all platforms).

Then there is even more obscure cases:
4. Imagine the files x/x.cpp and x/public/x.hpp (Both belonging to target X). Now, someone decides that the target Y (with code in y/) doesn’t need all the code in target X but just that one class. So, they add the file x/x.cpp to target X and target Y. If x/x.cpp contains the line “#include “public/x.hpp”, then target Y doesn’t even need the -I for x/public. How should automoc figure out that the file needs to be run through moc anyway?

And even longer with a bit of historic and technical background and focus on the technical problem:

The automoc concept and original implementation had been developed for the KDE project. IIRC, the original purpose was to speed up compilation by reducing the absolute number of translation units (i.e. number of .cpp files == number of compiler runs == number of linker inputs). This was achieved by two mechanism:

A) All header files that contained Q_OBJECT/GADGET are collected and run through moc, but the results of that were not added as translation units but rather were #include’ed in _one_ translation unit, which then was added to the target.

b) All source files that contained Q_OBJECT/GADGET needed to include the “<name>.moc” file - if such an include was spotted, the .cpp file itself was run through moc.

This tool was implemented outside of cmake and integrated into the build system as an additional target, on which the consuming target had a dependency. Much later, it was integrated into cmake, keeping this concept for various reasons.

Now back to the cmake implementation of automoc: When automoc is enabled for target T, cmake will add an additional target to the build - let’s call it TAM. T has a dependency on TAM, so TAM is always build _before_ T even starts to scan for its dependencies (in makefile based builds). Note that some generators don’t even have the requirement to scan for dependencies at compile time (i.e. MSBuild / Visual Studio does that by itself).
Scanning for dependencies is basically: “Run the preprocessor and tell me what files it would read if it were to do the actual work, then create a file with rules to describe these dependencies”.

Because when the cmake generator is run, it can’t actually know if there are indeed files that need to run through moc, it unconditionally adds the moc_T.cpp file to T (This is a problem for my current customer, because they have 500 targets where automoc is enabled based on whether Qt5::Core is a dependency or not - but only about 100 of these targets need automoc in the first place and it happens that Qt5::Core is a very low level dependency for them). The moc outputs that are #include’ed don’t need to be added to the target.
The problem here is, that once a target is created in CMake, you can’t add any files to it. So this has to be done that way.

Since the TAM target is build before T’s “scan for dependencies”, automoc can’t know what files _exactly_ are included in the project (unless given through add_executable/add_library). This makes an informed automatic decision in the above cases 3 and 4 practically impossible. And for case 1, this means: We’d actually have to consider _all_ files in _all_ -I directories, possibly including /usr/include and /usr/local/include.

So, what we’re left with is the actual command lines to the compiler, the include paths as defined in CMakeLists.txts. This _could_ be used to solve the case 2. But such a solution would be very error prone and still leaves case 1 to be sorted out somehow.
Post by Alan W. Irwin
I have already suggested some possible changes to the
documentation on the initial thread on the CMake mailing list and this
additional thread here on the CMake developer list.
But if nobody is
inspired to take immediate action on fixing the problem summarized
above (which would largely make the current documentation correct), I will write
up these documentation issues for the current automoc behaviour for
the bugtracker as well.
With the above background added to your knowledge, you might want to rethink if you consider this a bug in the automoc implementation.

I’ve read the cmake-qt(7) section about automoc several times now. I can’t actually figure out anything inside it that is plain _wrong_. However, I would suggest to change the documentation to:

The AUTOMOC target property controls whether cmake(1) inspects the C++ header and implementation
files in the target to determine if they require moc to be run, and to create rules to execute moc at the
appropriate time.

Note that it is recommended to explicitly list header files when declaring a target with add_executable
or add_library - even though this is only required when header and corresponding implementation file
are in different directories. {1}

moc needs to be run, if:
- A Q_OBJECT or Q_GADGET macro is found in a header file. In this case, the result will be put into
into a file named according to moc_<basename>.cpp. Multiple moc outputs generated that way will
be added to the target as one translation unit.

- The macro is found in a C++ implementation file. Following the Qt conventions, moc output will be
put into a file named according to <basename>.moc.
The implementation file may optionally use a preprocessor #include to include the .moc file (This is
typically done at the end of the file). If such an include is omitted, the .moc file will also be added to
the aforementioned translation unit.

Generated moc_*.cpp and *.moc files are placed in the build directory so it is convenient to set the
CMAKE_INCLUDE_CURRENT_DIR variable. {2}

The moc command line will consume the COMPILE_DEFINITIONS and INCLUDE_DIRECTORIES
target properties from the target it is being invoked for, and for the appropriate build configuration.

The AUTOMOC target property may be pre-set for all following targets by setting the
CMAKE_AUTOMOC variable. The AUTOMOC_MOC_OPTIONS target property may be populated
to set options to pass to moc. The CMAKE_AUTOMOC_MOC_OPTIONS variable may be populated
to pre-set the options for all following targets.

Cheers
Sascha

{1} I’d consider this too generic for _that_ part of the documentation, but it could be added: "Header files that are in the same directory as their implementation file will be automatically added to the target”.
{2} Maybe this should actually be changed to “so it might be required to set”
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-d
Craig Scott
2016-10-22 07:16:30 UTC
Permalink
The problem here is, that once a target is created in CMake, you can’t add
any files to it. So this has to be done that way.
Not actually true, the target_sources()
<https://cmake.org/cmake/help/latest/command/target_sources.html> command
can do precisely that. The following article shows some reasons why this is
particularly useful:

https://crascit.com/2016/01/31/enhanced-source-file-handling-with-target_sources/
--
Craig Scott
Melbourne, Australia
https://crascit.com
Alan W. Irwin
2016-10-22 20:10:17 UTC
Permalink
Post by Sascha Cunz
Post by Alan W. Irwin
Compilers know exactly where the header files are through
include_directories or the equivalent target PROPERTY so why can't
automoc find those same header files using similar logic?
In short: Because you really do not want automoc to do that.
The following applies to targets that you define as well as the external ones. The external one that you certainly can’t skip is QtCore, so I’ll explain it in terms of Qt5::Core.
By adding Qt5::Core to your target’s dependencies at least one -I option is added to the compiler, so it knows where to find Qt5 Core’s header files. At the same time you might have a subdirectory in your source tree that contains some of your header files that you also want to be searched, so you add i.e. “target_include_directories(MyTgt ${PROJECT_SOURCE_DIR}/FooModule)”. Now, the list of include directories for MyTgt contains two entries: Qt5::Core’s headers and FooModule. They are not distinguishable by any means. The question now is: How should automoc know which files you want to run through moc and which files not?
1. qcoreapplication.h - If you run automoc on that file, your target ends up defining the meta data for QCoreApplication, which is inefficient and will either lead to undefined behaviour or on most platforms to linker errors.
Independent of the technical things below, the decision to run or not run such headers through moc seems to be impossible to automate - One would need to either white or black list the directories used / not used for automoc.
2. FooModule/file1.h, which is included from file1.cpp in MyTgt - You might want to run that through moc, but actually only in the case that the compiler is building MyTgt. If the compiler is building another one of your targets that happens to require this include path, you end up the same as in case 1 above.
3. FooModule/file2.h, which does not have a corresponding .cpp file in MyTgt - (if this was on the system level: for example, not all files in /usr/include belong to the same project) This will lead to unresolved symbols in MyTgt (on most platforms) and the inability to actually execute MyTgt, unless it is linked against the library that actually contains the .cpp file (on all platforms).
4. Imagine the files x/x.cpp and x/public/x.hpp (Both belonging to target X). Now, someone decides that the target Y (with code in y/) doesn’t need all the code in target X but just that one class. So, they add the file x/x.cpp to target X and target Y. If x/x.cpp contains the line “#include “public/x.hpp”, then target Y doesn’t even need the -I for x/public. How should automoc figure out that the file needs to be run through moc anyway?
A) All header files that contained Q_OBJECT/GADGET are collected and run through moc, but the results of that were not added as translation units but rather were #include’ed in _one_ translation unit, which then was added to the target.
b) All source files that contained Q_OBJECT/GADGET needed to include the “<name>.moc” file - if such an include was spotted, the .cpp file itself was run through moc.
This tool was implemented outside of cmake and integrated into the build system as an additional target, on which the consuming target had a dependency. Much later, it was integrated into cmake, keeping this concept for various reasons.
Now back to the cmake implementation of automoc: When automoc is enabled for target T, cmake will add an additional target to the build - let’s call it TAM. T has a dependency on TAM, so TAM is always build _before_ T even starts to scan for its dependencies (in makefile based builds). Note that some generators don’t even have the requirement to scan for dependencies at compile time (i.e. MSBuild / Visual Studio does that by itself).
Scanning for dependencies is basically: “Run the preprocessor and tell me what files it would read if it were to do the actual work, then create a file with rules to describe these dependencies”.
Because when the cmake generator is run, it can’t actually know if there are indeed files that need to run through moc, it unconditionally adds the moc_T.cpp file to T (This is a problem for my current customer, because they have 500 targets where automoc is enabled based on whether Qt5::Core is a dependency or not - but only about 100 of these targets need automoc in the first place and it happens that Qt5::Core is a very low level dependency for them). The moc outputs that are #include’ed don’t need to be added to the target.
The problem here is, that once a target is created in CMake, you can’t add any files to it. So this has to be done that way.
Since the TAM target is build before T’s “scan for dependencies”, automoc can’t know what files _exactly_ are included in the project (unless given through add_executable/add_library). This makes an informed automatic decision in the above cases 3 and 4 practically impossible. And for case 1, this means: We’d actually have to consider _all_ files in _all_ -I directories, possibly including /usr/include and /usr/local/include.
So, what we’re left with is the actual command lines to the compiler, the include paths as defined in CMakeLists.txts. This _could_ be used to solve the case 2. But such a solution would be very error prone and still leaves case 1 to be sorted out somehow.
Hi Sascha:

I accept what you have said, and I very much appreciate your attempt
to educate me (and others here) in these C++/Qt/moc technical
considerations. Therefore, subject to some minor corrections such as
the subsequent one by Craig Scott I strongly urge you to put this
essential background information into the CMake FAQ so it is not lost
in the large traffic on this list.
Post by Sascha Cunz
The AUTOMOC target property controls whether cmake(1) inspects the C++ header and implementation
files in the target to determine if they require moc to be run, and to create rules to execute moc at the
appropriate time.
Note that it is recommended to explicitly list header files when declaring a target with add_executable
or add_library - even though this is only required when header and corresponding implementation file
are in different directories. {1}
That statement is not true in complete generality so I would suggest
the addition of the following qualifier

"Note that it is recommended" ==>
"Note that to assure consideration for moc processing it is recommended"

Also, it sounds from your footnote 1 that you would prefer not to have
all the details here about the exact rules for identifying the header
files to be scanned so I would suggest the following addition to the
above paragraph.

When the header is in the same directory as the C++ implementation
file there are additional possibilities for identifying it for
consideration for moc processing, see the automoc documentation.

And then the automoc documentation should be updated with those
same-directory possibilities clearly stated.
Post by Sascha Cunz
- A Q_OBJECT or Q_GADGET macro is found in a header file. In this case, the result will be put into
into a file named according to moc_<basename>.cpp. Multiple moc outputs generated that way will
be added to the target as one translation unit.
- The macro is found in a C++ implementation file. Following the Qt conventions, moc output will be
put into a file named according to <basename>.moc.
The implementation file may optionally use a preprocessor #include to include the .moc file (This is
typically done at the end of the file). If such an include is omitted, the .moc file will also be added to
the aforementioned translation unit.
Generated moc_*.cpp and *.moc files are placed in the build directory so it is convenient to set the
CMAKE_INCLUDE_CURRENT_DIR variable. {2}
The moc command line will consume the COMPILE_DEFINITIONS and INCLUDE_DIRECTORIES
target properties from the target it is being invoked for, and for the appropriate build configuration.
The AUTOMOC target property may be pre-set for all following targets by setting the
CMAKE_AUTOMOC variable. The AUTOMOC_MOC_OPTIONS target property may be populated
to set options to pass to moc. The CMAKE_AUTOMOC_MOC_OPTIONS variable may be populated
to pre-set the options for all following targets.
{1} I’d consider this too generic for _that_ part of the
documentation, but it could be added: "Header files that are in the same
directory as their implementation file will be automatically added to
the target”.
{2} Maybe this should actually be changed to “so it might be required to set”
Assuming you have no strong objections to the above further changes,
then I plan to wrap up our joint cmake-qt documentation changes into git
format-patch form for the convenience of the CMake developers here.
And I also plan to work on the automoc documentation using similar
language to what you have used above in the cmake-qt case with some
additions about the same-directory possibilities for identifying
headers that should moc'ed.

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-deve
Sebastian Holtermann
2016-10-22 17:49:44 UTC
Permalink
Post by Alan W. Irwin
[...]
Post by Sebastian Holtermann
Hi!
I tried your example.
It isn't complete, test_q_object.h needs an
#include <QObject>
MyClass(QObject *parent = 0) {;}
~MyClass(){;}
Thanks for that fix which indeed solves the linking issue.
Post by Sebastian Holtermann
With regards to automoc the
#include "moc_test_q_object.cpp"
in the end should not be neccessary since
#include "test_q_object.h"
already references to the header.
The problem is that this reference is not a direct path from the
source file but relies on include_directories.
CMake does not seem to populate automoc's scan list with files
from include_directories.
I tried to figure out why but this is quite complex.
I hope you are able to fix this along the lines I have mentioned
(which includes putting all generated results in the build tree
corresponding to the header) since using #include
"moc_test_q_object.cpp" in main.cpp is currently the only documented
way to use automoc (see, e.g.,
<https://cmake.org/cmake/help/v3.6/prop_tgt/AUTOMOC.html>).
As Sascha Cunz pointed out well, it is problematic to simply automoc any
header found in the include_directories. I think the current behaviour
is reasonable good. The documentation could be improved though to
mention the fullpath method.
Post by Alan W. Irwin
In sum, I hope you are willing to fix the currently documented automoc
"#include" method so it puts all generated results in the build tree
corresponding to the header, update the automoc documentation so you
also mention the "fullpath" alternative, and also similarly fix that
method so the location of the two generated files is in the build
directory corresponding to the header rather than the build directory
corresponding to the source file.
Actually I made an implementation in 3.6.0 that generated the moc files
in the a build tree subdirectory correspoding to the header path.
But that blew up on some projects because the generated paths got too
long for some compiĺers. That implementation was theefore reverted.
In 3.7 there is a new approatch that generates the moc files in
${CMAKE_BINARY_DIR}/
${TARGETNAME}_automoc.dir/
${HEADERNAME}_${HEADERPATHCHECKSUM}.cpp
This ensures that the paths don't get too long and that there won't be
any name collisions.
Post by Alan W. Irwin
My apologies for making suggestions for improvement without being able
to help you with the implementation (except testing of results), but
my C++ skills and CMake developer skills are just not up to it (as you
could probably tell from the required test_q_object.h fix you had to
suggest.)
We'll I'm just a spare time contributor but it's motivating to see that
someone cares about these issues as well.

-Sebastian
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://pub
Alan W. Irwin
2016-10-25 03:50:34 UTC
Permalink
Post by Sebastian Holtermann
Actually I made an implementation in 3.6.0 that generated the moc files
in the a build tree subdirectory correspoding to the header path.
But that blew up on some projects because the generated paths got too long
for some compiĺers. That implementation was theefore reverted.
In 3.7 there is a new approatch that generates the moc files in
${CMAKE_BINARY_DIR}/
${TARGETNAME}_automoc.dir/
${HEADERNAME}_${HEADERPATHCHECKSUM}.cpp
This ensures that the paths don't get too long and that there won't be any
name collisions.
Hi Sebastian:

Now that I have thought a bit more about this, you do need to
distinguish by target since those can have different automoc options,
and even if that is the same for the two targets, you would not want
multiple moc commands on the same header to generate the same output
file at the same time. So this looks like an excellent naming scheme
that will avoid all such collisions.

However, I see no sign of this new approach in my recent compilation
of 3.7.0-rc2, nor in the automoc documentation for the master branch
tip (or next branch tip). So is it really going to get into 3.7.0
(including the automoc documentation of this new approach)?

Also, I tested the simple test case modified to add an additional
target using the same source code and CMake-3.7.0-rc2. That currently
does generate the same filename for the two different moc output
results, and I was also surprised (considering the 3.7.0-rc2 automoc
documentation that states there would be a diagnostic warning of moc
output collisions) there was no collision diagnostic for this
particular case of two targets in the same directory. But your above
approach (once it gets into 3.7) should avoid all such collisions (and
thus make collision diagnostics moot).

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cma
Alan W. Irwin
2016-11-13 06:48:13 UTC
Permalink
On 2016-10-22 19:49+0200 Sebastian Holtermann wrote:

[...]
Post by Sebastian Holtermann
Actually I made an implementation in 3.6.0 that generated the moc files
in the a build tree subdirectory correspoding to the header path.
But that blew up on some projects because the generated paths got too long
for some compiĺers. That implementation was theefore reverted.
In 3.7 there is a new approatch that generates the moc files in
${CMAKE_BINARY_DIR}/
${TARGETNAME}_automoc.dir/
${HEADERNAME}_${HEADERPATHCHECKSUM}.cpp
This ensures that the paths don't get too long and that there won't be any
name collisions.
Hi Sebastian:

After a substantial break to finish off a different project, I have
now had a chance to return to the present topic using my attached
test_automoc project. (Also available in the cmake/test_automoc
subdirectory of the PLplot git master branch that can be accessed at
<https://sourceforge.net/p/plplot/plplot/ci/master/tree/>.) The
project builds 6 separate simple Qt5 applications that #include a
header that needs moc processing. The only differences between the
source code files for the various executables is the name and
directory location of that #include'd file and the various instructions
given to automoc (and in one case qt5_wrap_cpp) to process that file.

With that test project, I now confirm (sorry about the noise to the
contrary before) that automoc does use the approach you mentioned
above for CMake-3.7.0 to reduce the name collisions that occur for
that same project for earlier versions of CMake.

Concerning the collisions still expected for 3.7.0, the automoc
documentation (see
<https://cmake.org/cmake/help/v3.7/prop_tgt/AUTOMOC.html>) states the
following:

"However, if multiple source files in different directories do this
[i.e., contain an "#include "moc_<headerbasename>.cpp" when the header
name is <headerbasename>.h] then their generated moc files would
collide. In this case a diagnostic will be issued."

For the life of me, I cannot find a way to generate that diagnostic.
Instead, three different targets (two targets concerning the same
implementation code and header in the same directory and a third
target for a copy of that same implementation code and header in a
different directory) generate at build time a file named
moc_test_q_object.cpp in the same build directory at different times.
This is a clear example of a three-way name collision, but CMake does
not issue a diagnostic for any of these targets concerning that
collision contrary to the above documentation.

Could you please take a look at the three last executables configured
for this test case (helloworld_automoc_same_include,
helloworld_automoc_same_include1, and
helloworld_automoc_same_include2) to see why that collision diagnostic
is not being issued with cmake-3.7.0? Better yet, of course, would be
to solve these remaining name collisions completely by using a
modification of your idea above, i.e., for this special case where
users implementation code contained

#include "moc_<headerbasename>.cpp"

then moc should generate the file

${CMAKE_BINARY_DIR}/${TARGETNAME}_automoc.dir/${HEADERPATHCHECKSUM}/moc_${HEADERNAME}.cpp

Note, the generated moc file has the name expected by the #include so
I believe this idea would work so long as automoc automatically
appended
${CMAKE_BINARY_DIR}/${TARGETNAME}_automoc.dir/${HEADERPATHCHECKSUM} to
the target INCLUDE_DIRECTORIES property.

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
Sebastian Holtermann
2016-11-14 08:06:36 UTC
Permalink
Post by Alan W. Irwin
[...]
Post by Sebastian Holtermann
Actually I made an implementation in 3.6.0 that generated the moc files
in the a build tree subdirectory correspoding to the header path.
But that blew up on some projects because the generated paths got too
long for some compiĺers. That implementation was theefore reverted.
In 3.7 there is a new approatch that generates the moc files in
${CMAKE_BINARY_DIR}/
${TARGETNAME}_automoc.dir/
${HEADERNAME}_${HEADERPATHCHECKSUM}.cpp
This ensures that the paths don't get too long and that there won't be
any name collisions.
After a substantial break to finish off a different project, I have
now had a chance to return to the present topic using my attached
test_automoc project. (Also available in the cmake/test_automoc
subdirectory of the PLplot git master branch that can be accessed at
<https://sourceforge.net/p/plplot/plplot/ci/master/tree/>.) The
project builds 6 separate simple Qt5 applications that #include a
header that needs moc processing. The only differences between the
source code files for the various executables is the name and
directory location of that #include'd file and the various instructions
given to automoc (and in one case qt5_wrap_cpp) to process that file.
With that test project, I now confirm (sorry about the noise to the
contrary before) that automoc does use the approach you mentioned
above for CMake-3.7.0 to reduce the name collisions that occur for
that same project for earlier versions of CMake.
Concerning the collisions still expected for 3.7.0, the automoc
documentation (see
<https://cmake.org/cmake/help/v3.7/prop_tgt/AUTOMOC.html>) states the
"However, if multiple source files in different directories do this
[i.e., contain an "#include "moc_<headerbasename>.cpp" when the header
name is <headerbasename>.h] then their generated moc files would
collide. In this case a diagnostic will be issued."
For the life of me, I cannot find a way to generate that diagnostic.
Instead, three different targets (two targets concerning the same
implementation code and header in the same directory and a third
target for a copy of that same implementation code and header in a
different directory) generate at build time a file named
moc_test_q_object.cpp in the same build directory at different times.
This is a clear example of a three-way name collision, but CMake does
not issue a diagnostic for any of these targets concerning that
collision contrary to the above documentation.
Could you please take a look at the three last executables configured
for this test case (helloworld_automoc_same_include,
helloworld_automoc_same_include1, and
helloworld_automoc_same_include2) to see why that collision diagnostic
is not being issued with cmake-3.7.0? Better yet, of course, would be
to solve these remaining name collisions completely by using a
modification of your idea above, i.e., for this special case where
users implementation code contained
#include "moc_<headerbasename>.cpp"
then moc should generate the file
${CMAKE_BINARY_DIR}/${TARGETNAME}_automoc.dir/${HEADERPATHCHECKSUM}/moc_${HEADERNAME}.cpp
Note, the generated moc file has the name expected by the #include so
I believe this idea would work so long as automoc automatically
appended
${CMAKE_BINARY_DIR}/${TARGETNAME}_automoc.dir/${HEADERPATHCHECKSUM} to
the target INCLUDE_DIRECTORIES property.
Hi Alan,

the automoc diagnostic checks for name collisions within a single target
only, not across multiple targets - as in your example.

The problem I see is that all moc files included by the
#include "moc_<headerbasename>.cpp"
scheme get generated in ${CMAKE_BINARY_DIR}.
It would be better to generate them in
${CMAKE_BINARY_DIR}/${TARGETNAME}_automoc.dir
to avoid inter target name collisions.
Your solution using the path checksum as well would be event better
as it avoids name collisions even within a target.
The problem there is though that it would require to add
a .cpp file specific -I compiler statement for every .cpp file
that includes a moc file.
This is hard to do with the current automoc implementation.
I would not want to do it.
What probably could be done is to add
${CMAKE_BINARY_DIR}/${TARGETNAME}_automoc.dir
to the INCLUDE_DIRECTORIES of the target and then generate all
#included moc file there, accepting the risk of intra target name
collisions.

-Sebastian
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http
Alan W. Irwin
2016-11-14 11:41:06 UTC
Permalink
Post by Sebastian Holtermann
What probably could be done is to add
${CMAKE_BINARY_DIR}/${TARGETNAME}_automoc.dir
to the INCLUDE_DIRECTORIES of the target and then generate all
#included moc file there, accepting the risk of intra target name
collisions.
Hi Sebastian:

Your compromise idea above sounds good to me!

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state
implementation for stellar interiors (freeeos.sf.net); the Time
Ephemerides project (timeephem.sf.net); PLplot scientific plotting
software package (plplot.sf.net); the libLASi project
(unifont.org/lasi); the Loads of Linux Links project (loll.sf.net);
and the Linux Brochure Project (lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers
Sebastian Holtermann
2016-11-14 12:25:18 UTC
Permalink
Post by Alan W. Irwin
Post by Sebastian Holtermann
What probably could be done is to add
${CMAKE_BINARY_DIR}/${TARGETNAME}_automoc.dir
to the INCLUDE_DIRECTORIES of the target and then generate all
#included moc file there, accepting the risk of intra target name
collisions.
Your compromise idea above sounds good to me!
Btw. I liked your
${CMAKE_BINARY_DIR}/
${TARGETNAME}_automoc.dir/
${HEADERPATHCHECKSUM}/
moc_${HEADERNAME}.cpp
approach.

It could be used for the moc_<autoname>.cpp files that are not
manually #included and therefore can have any name.

Over the current
${CMAKE_BINARY_DIR}/
${TARGETNAME}_automoc.dir/
moc_${HEADERNAME}_${HEADERPATHCHECKSUM}.cpp
scheme it has the advantages that
1) moc_<autoname>.cpp files are grouped by their source directory
2) ${HEADERNAME} is kept intact and does not get shortened
3) fewer weird looking checksum names ;)

1) and 2) are generally helpful to find and debug moced files I think.

There are a some other changes to the automoc system I would like to
propose / work on. I'm currently busy with an other project though.

-Sebastian
--
Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers
Loading...