Support for projects using Qt Framework

Since out bugtracker does not support meta-issues, I'll put it here.

What is needed:

  • Custom build rules including support for code generation (i.e., generated C++ files need to be included into list of source files and then compiled)
  • Usages
  • Support for cusom build rules in usages

What is need for IDE integration:

  • Possibility to distinguish hand-written and generated source files

This list may be updated in future.

FWIW, usages are my priority for the 4.5 release.

What is current state of usages? Is it worth to try to use them?

They work, basically, but will probably see a fair bit of change once I dig into them in the next release cycle.

I've written a Premake extension allowing to use Qt with gmake on Unix-like systems (including Mac).
It requires patch [1] to work. You can see and download code here:

https://gist.github.com/1312957

Current status: it's able to build simple Qt project which uses forms and resources. Sample project file:

require "qt-support"
 
solution "ExampleSolution"
    configurations { "Debug", "Release" }
 
    project "ExampleProject"
        kind "WindowedApp"
        language "C++"
        files {
            "src/**.h",
            "src/**.cpp",
            "src/**.ui",
            "src/**.qrc"
        }
        uses { "QtGui", "QtXml" }
        configuration "Debug"
            defines { "DEBUG" }
            flags { "Symbols" }
 
        configuration "Release"
            defines { "NDEBUG", "QT_NO_DEBUG" }
            flags { "Optimize" }

[1] https://sourceforge.net/tracker/?func=detail&aid=3353719&group_id=71616&...

This looks great! Thanks for the hard work.

Unfortunately, I can't quite use it yet, as I need windows support.

I'll stay tuned : )

This looks great! Thanks for the hard work.

Unfortunately, I can't quite use it yet, as I need windows support.

I'll stay tuned : )

daleha: I haven't tested windows at all, but if you are using gmake, you can try to use current version. You will need to set --qtdir to path to your Qt installation (where bin, lib, mkspecs are placed).

Please report if there are any issues.

Unfortunately, I am using visual studios for the compilation, so the output format must be in csproj/vcsproj format.

@starkos: I'd like to get Qt support inside mainline Premake eventually, so I'd like you to review implementation to make sure I've chosen right direction. Note: I'm not going to allow using Qt in one configuration of project and not using it in another.

Hey @annulen—sorry, I'm totally swamped at the moment, but I will try to look at this as soon as I can. I'd like to see this get integrated as well.

I don't want to bury Qt stuff deeply in gmake action, but I really need to generate Makefile rules *after* baking.

I think I should save data structure like premake.qt.codegencallbacks in my current implementation into project table, and then write rules in gmake action. So gmake action won't know anything about Qt stuff.

I think this look like a solid approach. I like the plug-and-play approach. I don't know enough about Qt development to comment on the specifics of the actual API. On the Premake side, I have two suggestions:

* I'd prepend a "qt" to the API functions to avoid possible conflicts, particularly "uses" should be "qtuses" (IMHO).

* I'd use Premake's API functions. Currently, it looks like you can only have one Qt project in your solution, because of code like this:

function uidir(dir)
    premake.qt.uidir = dir
end

If this were a proper Premake API, you could have unique uidir values per multiple projects.

One more suggestion: I'd recommend decoupling this from your make footer patch, so they can be considered separately. For the WiiDev support, I added the make.settings() function, which is currently only called for configuration blocks in gmake_cpp.lua. You could follow this same pattern to get the Qt rules into the makefile, without having to worry about building out a whole public API.

>I think this look like a solid approach.

I'd rather called it "quick&dirty" approach. To get thinks done properly a part of code should be run after baking. For example, current implementation:
1) will break if somebody places uses before last files block
2) doesn't appreciate excludes
3) + see the top comment of qt-support.lua

However, it somehow implements almost all features required from "good Qt support" (read: imitates behavior of QMake).

>I don't know enough about Qt development to comment on the specifics of the actual API.

I can tell you what it should do.

Basically, support of Qt is about 2 things:

  1. Like with any other library, we have sets of cflags and link flags per module + global Qt flags
  2. We have several kinds of code generation:
    1. Simple compilation: files of kind "A" are transformed into files of kind "B"
      • Translation source files *.ts are compiled to binary translations *.qm
    2. Generation of source files
      • *.ui (User Interface) files are compiled to header files ui_*.h, which are included by project source files
      • *.qrc files (lists of embedded resources) are compiled into qrc_*.cpp files which should be compiled and linked into target
    3. Generation of Meta-Object Code. Similar to previous kind but more tough.
      • Header files which contain Q_OBJECT macro are "compiled" to moc_*.cpp files which are just plain C++ sources containing some meta-object code and all needed includes
      • Source files which contain #include "sourcefilename.moc" are "compiled" to "sourcefilename.moc" containing the same kind of meta-object code but without includes, which is just included into sourcefilename.cpp.

>I'd prepend a "qt" to the API functions to avoid possible conflicts, particularly "uses" should be "qtuses"

I wished to integrate with future uses infrastructure and possibly migrate to it behind the scenes when it's ready. I can rename the function into "qt" (in qmake you do e.g. "QT += network xml" and get selected modules)

>I'd use Premake's API functions.

Problem is that currently I cannot declare API functions outside of api.lua, and it doesn't fell right for me to have Qt-specific stuff there while Qt support is experimental and won't be merged soon. Also, Qt is not a separate language, so I'd preferred to keep Qt-related stuff inside some Qt module in Premake.

If it's appropriate I can add function which will allow to create new APIs outside of api.lua

>Currently, it looks like you can only have one Qt project in your solution

Not really, it affects current project, and next project can redefine it or keep the same (path is relative)

>I'd recommend decoupling this from your make footer patch, so they can be considered separately. For the WiiDev support, I added the make.settings() function, which is currently only called for configuration blocks in gmake_cpp.lua.

Footer patch is almost ready, it also brings other kinds of makefile sections

I like an idea of having make.settings() to do thing like enabling colors or modifying output format (e.g. print "CC filename.c" during compilation), but I can't imagine build rules to be a kind of make settings :)

Actually, I can decouple Qt support from make sections by introducing 2 new entities:
* project variables
* custom build steps (where step is a combination of target file, explicit dependencies, and producing command)

AFAIK, these facilities are supported at least by make and Visual Studio [1,2]. If we get them for Xcode too, it would be fine (but I don't know anything about Xcode project format(s) [3]). I don't care about other IDEs at least for now.

[1] http://msdn.microsoft.com/en-us/library/a4xbdz1e.aspx
[2] http://industriousone.com/post/custom-file-rules, http://industriousone.com/topic/visual-studio-custom-build-rules
[3] Actually I don't know about VS format more than about Xcode, however I'm ready to learn it if needed :)

Trying to explain things briefly, I've written imaginary action-independent Premake extension which adds Qt support using non-existing features, described in opening post:

https://gist.github.com/1350926

I've declared mocdir and friends as "external" API functions, however I cannot reliably use API fields before baking.

I think is coming out well. A couple of hasty thoughts:

* I'm not going to put this into 4.4. Partly because I just have to draw the line somewhere or I'll never get 4.4 released, but also because I think I think we can usages and custom compiler rules into 4.5, which will really improve it.

* I'm not sure if this should be part of the "core" Premake, or if it should distributed as an extension or add-on (with improved support for such things in Premake core instead). At the moment I'm probably leaning more toward putting it into Premake.

* Nice work on this.

>I'm not going to put this into 4.4.

That's OK.

>I'm not sure if this should be part of the "core" Premake, or if it should distributed as an extension or add-on

I think it should go into Premake, however it would be nice if it could be used as add-on for 4.4

I think we should find a reasonable compromise between "the right thing" and the current state of script. Among all kinds of issues mentioned in the beginning of the script, I think only first two are real show stoppers, i.e. non-declarative behavior of "uses" and "mocdir" and friends. This stuff is against Premake spirit and can scare away newcomers. I wish these issues were solved for 4.4 release.

Non-portability of makefiles and absence of support for anything other than gmake are not so significant, I can just embed this script into my Premake plugin for Qt Creator (it uses gmake/gcc on *nix and gmake/mingw on windows under the hood), and start promoting Premake in Qt community as is (probably I need to add Windows/gmake though).

Also, for my particular needs I'd like to have a possibility to specify explicit qtdir per configuration/platform.

If you haven't already, make sure we've got these filed as bugs so I can work them for 4.4.

Probably they could be solved with post-bake hook(s)

Found temporary solution: renamed gmake action into _gmake, added my own gmake action, and used action chaining. Now gmake action behaves like usual but can run my code before anything else...

I've reworked my addon. Now it's free from mentioned showstoppers and allows to set qtdir per configuration. So it's almost ready for production ;)

If you want to look at new version, you will find it in the same place as before.

Now I'd like to solve smaller issue. My API allows creation of output directories directories (mocdir, uidir, rccdir, I also want to add qmdir for translations), which ideally should be treated the same way as objdir (processed in builduniquedirs to prevent clash between configurations). However, builduniquedirs is local so I even cannot replace it from outside.

Alternatively, I can intoduce some kind of pattern, e.g. mocdir "%objdir/_moc" (currently I use "$(OBJDIR)/_moc in projects, but it's just a play with make).

Also, Makefiles should support some kind of "list of unique dirs" - when I create rules for mocdir, uidir, and rccdir, I get 3 warnings about overriding commands for target `obj/Debug' if default values are used.

I can make builduniquedirs accessible…I'll try to get to that today. I don't understand the second part about the list thing.

>I can make builduniquedirs accessible

It's not a big deal to remove "local", however I don't think it's a good approach to replace it. Probably it would be better to make it extensible, ie. work not only for objdir.

>I don't understand the second part about the list thing.

Generated makefiles contain distinct targets $(TARGETDIR) and $(OBJDIR), the next code to create them:

$(TARGETDIR):                                                                                                                               
>---@echo Creating $(TARGETDIR)                                                            
ifeq (posix,$(SHELLTYPE))                                                  
>---$(SILENT) mkdir -p $(TARGETDIR)                                        
else      
>---$(SILENT) mkdir $(subst /,\\,$(TARGETDIR))  
endif
 
$(OBJDIR):                                                                                                                                  
>---@echo Creating $(OBJDIR)                                                                                
ifeq (posix,$(SHELLTYPE))                                                     
>---$(SILENT) mkdir -p $(OBJDIR)            
else                              
>---$(SILENT) mkdir $(subst /,\\,$(OBJDIR))                                  
endif

(>--- is tab)

and the next code for clean:

ifeq (posix,$(SHELLTYPE))      
>---$(SILENT) rm -f  $(TARGET)              
>---$(SILENT) rm -rf $(OBJDIR)                    
else              
>---$(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET)) 
>---$(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR))    
endif 

It would be better to generalize it to arbitrary list of dirs, and don't create separate rules for same dir (if $(MOCDIR) and others point to $(OBJDIR) and there is a rule for each one, it causes Makefile warnings)

It could be solved with code like this:

$(GENERATED_DIRS):
>---@echo Creating directories...                                                           
ifeq (posix,$(SHELLTYPE))                                                  
>---$(SILENT) mkdir -p $(TARGETDIR)     
# Other dirs follow
else      
>---$(SILENT) mkdir $(subst /,\\,$(TARGETDIR))  
# Other dirs  follow
endif

What about builduniquedirs, I can unconditionally put mocdir and friends under objdir, i.e. for

mocdir "_moc"

create $(MOCDIR) as $(OBJDIR)/_moc. Maybe counter-intuitive though.

I've worked around this issue: all Qt-specific output directories are created and erased together now. If e.g. mocdir is left to be default, $(MOCDIR) not appended to QT_DIRS variable, but if it's set to non-default in any configuration, $(MOCDIR) is created in $(QT_DIRS): target

The next important issue with Qt is support of static Qt builds. It could be resolved by checking if libQtCore is shared or static, but due to specific of Premake
1) I cannot be sure if Premake is being run on system where build will actually happen;
2) Even if I can be sure in it, I don't have access to full path of the library which will be linked.

So I think the best solution will be Qt-specific flag, e.g. "StaticQt". Is it OK to use flags for this purpose?

Also, I need to add special behavior if project is a Qt plugin. Probably I should also use flag for this, shouldn't I?

Example solution with several Qt examples, ported to Premake, can be found here (work in progress):

https://github.com/annulen/qt-examples-premake

Hi annulen; I'm trying to build your examples but I get: attempt to call global 'newapis' (a nil value)
I'm using premake-4.4-beta3-windows

textral: you need special branch of Premake, containing several patches:
git@github.com:annulen/premake-annulen.git (branch 'qt')

I'm planning to release tarball and binaries of this branch soon