├── _manifest.lua ├── License.md ├── qtmodules.qt5.lua ├── qtmodules.qt6.lua ├── _preload.lua ├── Readme.md └── qt.lua /_manifest.lua: -------------------------------------------------------------------------------- 1 | 2 | return { 3 | "_preload.lua", 4 | "qt.lua", 5 | "qtmodules.qt5.lua", 6 | "qtmodules.qt6.lua" 7 | } 8 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /qtmodules.qt5.lua: -------------------------------------------------------------------------------- 1 | 2 | -- 3 | -- The available modules' definitions. 4 | -- Use the keys with qtmodule. For instance `qtmodule { "core", "gui" }` to use QtCore and QtGui 5 | -- 6 | premake.extensions.qt.modules.qt5 = { 7 | core = { 8 | name = "Core", 9 | include = "QtCore", 10 | defines = { "QT_CORE_LIB" } 11 | }, 12 | gui = { 13 | name = "Gui", 14 | include = "QtGui", 15 | defines = { "QT_GUI_LIB" } 16 | }, 17 | multimedia = { 18 | name = "Multimedia", 19 | include = "QtMultimedia", 20 | defines = { "QT_MULTIMEDIA_LIB" } 21 | }, 22 | network = { 23 | name = "Network", 24 | include = "QtNetwork", 25 | defines = { "QT_NETWORK_LIB" } 26 | }, 27 | opengl = { 28 | name = "OpenGL", 29 | include = "QtOpenGL", 30 | links = { "OpenGL32" }, 31 | defines = { "QT_OPENGL_LIB" } 32 | }, 33 | positioning = { 34 | name = "Positioning", 35 | include = "QtPositioning", 36 | defines = { "QT_POSITIONING_LIB" } 37 | }, 38 | printsupport = { 39 | name = "PrintSupport", 40 | include = "QtPrintSupport", 41 | defines = { "QT_PRINTSUPPORT_LIB" } 42 | }, 43 | qml = { 44 | name = "Qml", 45 | include = "QtQml", 46 | defines = { "QT_QML_LIB" } 47 | }, 48 | quick = { 49 | name = "Quick", 50 | include = "QtQuick", 51 | defines = { "QT_QUICK_LIB" } 52 | }, 53 | quickcontrols2 = { 54 | name = "QuickControls2", 55 | include = "QtQuickControls2", 56 | defines = { "QT_QUICKCONTROLS2_LIB" } 57 | }, 58 | sensors = { 59 | name = "Sensors", 60 | include = "QtSensors", 61 | defines = { "QT_SENSORS_LIB" } 62 | }, 63 | sql = { 64 | name = "Sql", 65 | include = "QtSql", 66 | defines = { "QT_SQL_LIB" } 67 | }, 68 | svg = { 69 | name = "Svg", 70 | include = "QtSvg", 71 | defines = { "QT_SVG_LIB" } 72 | }, 73 | testlib = { 74 | name = "Test", 75 | include = "QtTest", 76 | defines = { "QT_TESTLIB_LIB" } 77 | }, 78 | websockets = { 79 | name = "WebSockets", 80 | include = "QtWebSockets", 81 | defines = { "QT_WEBSOCKETS_LIB" } 82 | }, 83 | widgets = { 84 | name = "Widgets", 85 | include = "QtWidgets", 86 | defines = { "QT_WIDGETS_LIB" } 87 | }, 88 | xml = { 89 | name = "Xml", 90 | include = "QtXml", 91 | defines = { "QT_XML_LIB" } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /qtmodules.qt6.lua: -------------------------------------------------------------------------------- 1 | 2 | -- 3 | -- The available modules' definitions. 4 | -- Use the keys with qtmodule. For instance `qtmodule { "core", "gui" }` to use QtCore and QtGui 5 | -- 6 | premake.extensions.qt.modules.qt6 = { 7 | core = { 8 | name = "Core", 9 | include = "QtCore", 10 | defines = { "QT_CORE_LIB" } 11 | }, 12 | entrypoint = { 13 | name = "EntryPoint", 14 | defines = { "QT_ENTRY_POINT_LIB" } 15 | }, 16 | gui = { 17 | name = "Gui", 18 | include = "QtGui", 19 | defines = { "QT_GUI_LIB" } 20 | }, 21 | multimedia = { 22 | name = "Multimedia", 23 | include = "QtMultimedia", 24 | defines = { "QT_MULTIMEDIA_LIB" } 25 | }, 26 | network = { 27 | name = "Network", 28 | include = "QtNetwork", 29 | defines = { "QT_NETWORK_LIB" } 30 | }, 31 | opengl = { 32 | name = "OpenGL", 33 | include = "QtOpenGL", 34 | links = { "OpenGL32" }, 35 | defines = { "QT_OPENGL_LIB" } 36 | }, 37 | positioning = { 38 | name = "Positioning", 39 | include = "QtPositioning", 40 | defines = { "QT_POSITIONING_LIB" } 41 | }, 42 | printsupport = { 43 | name = "PrintSupport", 44 | include = "QtPrintSupport", 45 | defines = { "QT_PRINTSUPPORT_LIB" } 46 | }, 47 | qml = { 48 | name = "Qml", 49 | include = "QtQml", 50 | defines = { "QT_QML_LIB" } 51 | }, 52 | quick = { 53 | name = "Quick", 54 | include = "QtQuick", 55 | defines = { "QT_QUICK_LIB" } 56 | }, 57 | quickcontrols2 = { 58 | name = "QuickControls2", 59 | include = "QtQuickControls2", 60 | defines = { "QT_QUICKCONTROLS2_LIB" } 61 | }, 62 | sensors = { 63 | name = "Sensors", 64 | include = "QtSensors", 65 | defines = { "QT_SENSORS_LIB" } 66 | }, 67 | sql = { 68 | name = "Sql", 69 | include = "QtSql", 70 | defines = { "QT_SQL_LIB" } 71 | }, 72 | svg = { 73 | name = "Svg", 74 | include = "QtSvg", 75 | defines = { "QT_SVG_LIB" } 76 | }, 77 | testlib = { 78 | name = "Test", 79 | include = "QtTest", 80 | defines = { "QT_TESTLIB_LIB" } 81 | }, 82 | websockets = { 83 | name = "WebSockets", 84 | include = "QtWebSockets", 85 | defines = { "QT_WEBSOCKETS_LIB" } 86 | }, 87 | widgets = { 88 | name = "Widgets", 89 | include = "QtWidgets", 90 | defines = { "QT_WIDGETS_LIB" } 91 | }, 92 | xml = { 93 | name = "Xml", 94 | include = "QtXml", 95 | defines = { "QT_XML_LIB" } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /_preload.lua: -------------------------------------------------------------------------------- 1 | 2 | -- 3 | -- To avoid qt.lua re-including _preload 4 | -- 5 | premake.extensions.qt = true 6 | 7 | 8 | -- 9 | -- Set the path where Qt is installed 10 | -- 11 | premake.api.register { 12 | name = "qtpath", 13 | scope = "config", 14 | kind = "path", 15 | tokens = true 16 | } 17 | 18 | -- 19 | -- By default, Qt modules' include directories are added as regular include directories, 20 | -- meaning they might issue warnings. 21 | -- You can use this option so that the include directories are instead added as "external" ones 22 | -- so that compilers supporting this won't ever issue any warnings on those includes. 23 | premake.api.register { 24 | name = "qtuseexternalinclude", 25 | scope = "config", 26 | kind = "boolean" 27 | } 28 | 29 | -- 30 | -- Set the binary path. By default, its `qtpath .. "/bin"`. Use 31 | -- this command to override it. 32 | -- 33 | premake.api.register { 34 | name = "qtbinpath", 35 | scope = "config", 36 | kind = "path", 37 | tokens = true 38 | } 39 | 40 | -- 41 | -- Set the include path. By default, its `qtpath .. "/include"`. Use 42 | -- this command to override it. 43 | -- 44 | premake.api.register { 45 | name = "qtincludepath", 46 | scope = "config", 47 | kind = "path", 48 | tokens = true 49 | } 50 | 51 | -- 52 | -- Set the library path. By default, its `qtpath .. "/lib"`. Use 53 | -- this command to override it. 54 | -- 55 | premake.api.register { 56 | name = "qtlibpath", 57 | scope = "config", 58 | kind = "path", 59 | tokens = true 60 | } 61 | 62 | -- 63 | -- Set the prefix of the libraries ("Qt4" or "Qt5" usually) 64 | -- 65 | -- Note: now by default it's created from the major_version string passed to the enable 66 | -- function. So if you don't use qtprefix, by default it'll be "Qt5", and if you used 67 | -- premake.extensions.qt.enable("6") then it'll be "Qt6". This is left here for backward 68 | -- compatibility and corner cases, but should no longer be needed in most cases. 69 | -- 70 | premake.api.register { 71 | name = "qtprefix", 72 | scope = "config", 73 | kind = "string" 74 | } 75 | 76 | -- 77 | -- Set a suffix for the libraries ("d" usually when using Debug Qt libs) 78 | -- 79 | premake.api.register { 80 | name = "qtsuffix", 81 | scope = "config", 82 | kind = "string" 83 | } 84 | 85 | -- 86 | -- Link the qtmain lib on Windows. 87 | -- 88 | -- Note: On Qt6, this will no longer work. Instead, the "entrypoint" module should be added. 89 | -- Using this will automatically add said module (for backward compatibility) 90 | -- 91 | premake.api.register { 92 | name = "qtmain", 93 | scope = "config", 94 | kind = "boolean" 95 | } 96 | 97 | -- 98 | -- Specify the modules to use (will handle include paths, links, etc.) 99 | -- See premake.extensions.qt.modules for a list of available modules. 100 | -- 101 | premake.api.register { 102 | name = "qtmodules", 103 | scope = "config", 104 | kind = "string-list" 105 | } 106 | 107 | -- 108 | -- Specify the path, relative to the current script, where the files generated 109 | -- by Qt will be created. If this command is not used, the default behavior 110 | -- is to generate those files in the objdir. 111 | -- 112 | premake.api.register { 113 | name = "qtgenerateddir", 114 | scope = "config", 115 | kind = "path", 116 | tokens = true, 117 | pathVars = true 118 | } 119 | 120 | -- 121 | -- Specify a list of custom options to send to the Qt moc command line. 122 | -- 123 | premake.api.register { 124 | name = "qtmocargs", 125 | scope = "config", 126 | kind = "string-list" 127 | } 128 | 129 | -- 130 | -- Specify a list of custom options to send to the Qt lrelease command line. 131 | -- 132 | premake.api.register { 133 | name = "qtlreleaseargs", 134 | scope = "config", 135 | kind = "string-list" 136 | } 137 | 138 | -- 139 | -- Specify the path, relative to the current script, where the qm files generated 140 | -- by Qt will be created. If this command is not used, the default behavior 141 | -- is to generate those files in the target directory. 142 | -- 143 | premake.api.register { 144 | name = "qtqmgenerateddir", 145 | scope = "config", 146 | kind = "path", 147 | tokens = true, 148 | pathVars = true 149 | } 150 | 151 | -- 152 | -- Specify a list of custom options to send to the Qt uic command line. 153 | -- 154 | premake.api.register { 155 | name = "qtuicargs", 156 | scope = "config", 157 | kind = "string-list" 158 | } 159 | 160 | -- 161 | -- Specify a list of custom options to send to the Qt rcc command line. 162 | -- 163 | premake.api.register { 164 | name = "qtrccargs", 165 | scope = "config", 166 | kind = "string-list" 167 | } 168 | 169 | -- 170 | -- Specify the version of Qt. 171 | -- This is used to determine the private header path when adding private modules. 172 | -- If unspecified, the addon will scan `qtincludepath .. "/QtCore/qconfig.h"` and `qglobal.h` 173 | -- for the version string. 174 | -- 175 | premake.api.register { 176 | name = "qtversion", 177 | scope = "config", 178 | kind = "string" 179 | } 180 | 181 | -- 182 | -- This command is used to tell Qt tools to store their command line arguments 183 | -- in a file if the size of the command line is greater than the limit 184 | -- 185 | premake.api.register { 186 | name = "qtcommandlinesizelimit", 187 | scope = "config", 188 | kind = "integer" 189 | } 190 | 191 | -- 192 | -- Private use only : used by the addon to know if qt has already been enabled or not 193 | -- 194 | premake.api.register { 195 | name = "qtenabled", 196 | scope = "project", 197 | kind = "boolean" 198 | } 199 | 200 | 201 | -- 202 | -- Always load 203 | -- 204 | return function () return true end 205 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | Qt Addon 2 | ======== 3 | 4 | This addon allows you to generate a projects / solutions with Qt support by 5 | automatically adding the correct custom build command to handle the Qt specific 6 | stuff (such as invoking the `moc` command, the `uic` one, etc.) 7 | 8 | **Beware though that those custom rules are only created when the solutions / 9 | projects are built using Premake** ! You need to re-run Premake when adding 10 | new Qt classes, UIs, etc. or when you add **Q_OBJECT** or **Q_GADGET** to one 11 | of your existing classes. 12 | 13 | It should support any action which has support for custom build commands, but 14 | I only tested this addon with the Visual Studio actions, so I'm not sure of its 15 | behavior when using gmake, or any other action. 16 | 17 | Please feel free to drop a comment, issue or whatever if you notice a bug. Also, 18 | if you take the time to do so, please also take the time to create a small 19 | reproductible scenario that you can attach to the issue :) 20 | 21 | 22 | How to use 23 | ========== 24 | 25 | Clone this repository some place where Premake will be able to find it. Then 26 | in your project's Premake script, include the main file like this : 27 | 28 | ```lua 29 | require( "premake-qt/qt.lua" ) 30 | 31 | -- this line is optional, but it avoids writting premake.extensions.qt to 32 | -- call the plugin's methods. 33 | local qt = premake.extensions.qt 34 | ``` 35 | 36 | Then in the projects that you want to enable to Qt, just add this : 37 | 38 | ```lua 39 | -- be carefull, this function enables Qt only for the current configuration. 40 | -- So if you want to enable it on all configuration, be sure that no filter 41 | -- is active when calling this (or reset the filter using `filter {}` 42 | qt.enable() 43 | ``` 44 | 45 | 46 | API 47 | === 48 | 49 | The following API commands will allow you to customize Qt: what version are 50 | you building against, what custom options do you want to send to the Qt build 51 | tools, etc. They only have an effect if the project has been enabled to Qt. 52 | 53 | Most of the API commands of this addon are scoped to the current configuration, 54 | so unless specified otherwise, assume that the documented command only applies 55 | to the current configuration block. 56 | 57 | ##### qtpath "path" 58 | 59 | Setup the path where Qt include and lib folders are found. If this is not used, 60 | the addon will try to get the path from the `QTDIR` or `QT_DIR` environment variable. 61 | 62 | When setting this, the addon will automatically try to locate the binaries, include 63 | and libraries in the `include`, `lib` and `bin` subfolders of the specified path. 64 | 65 | If your includes, libraries and binaries are in separate folders (for instance on 66 | Unix they might be in /usr/include, /usr/lib or whatever) you can use the 67 | `qtincludepath`, `qtlibpath` and `qtbinpath` API commands instead. 68 | 69 | ##### qtincludepath "path" 70 | 71 | Set the path for the Qt headers. If this is not used, the addon will set the 72 | includepath to the `include` child folder of the one set by `qtpath`, or one of the 73 | environment variable. 74 | 75 | ##### qtuseexternalinclude ( boolean ) 76 | 77 | By default, Qt modules' include directories are added as regular include directories, 78 | meaning they might issue warnings. 79 | You can use this option so that the include directories are instead added as "external" ones 80 | so that compilers supporting this won't ever issue any warnings on those includes. 81 | 82 | ##### qtlibpath "path" 83 | 84 | Set the path for the Qt libraries. If this is not used, the addon will set the 85 | includepath to the `lib` child folder of the one set by `qtpath`, or one of the 86 | environment variable. 87 | 88 | ##### qtbinpath "path" 89 | 90 | Set the path for the Qt binaries. If this is not used, the addon will set the 91 | includepath to the `bin` child folder of the one set by `qtpath`, or one of the 92 | environment variable. 93 | 94 | ##### qtprefix "prefix" 95 | 96 | Specify a prefix used by the libs. For instance, when using the default Qt5 97 | installation, for the widgets module, the lib is named `Qt5Widgets.lib`, so you 98 | must set `Qt5` as the prefix. 99 | 100 | ##### qtsuffix "suffix" 101 | 102 | This one is only used when linking against debug or custom versions of Qt. For 103 | instance, in debug, the libs are suffixed with a `d`. And when building your 104 | own version of Qt, you might want to suffix the x64 and x86 versions differently. 105 | 106 | ##### qtmain true 107 | 108 | Windows only. If this is used, the `qtmain` library will be linked to the current 109 | project on the current config. 110 | 111 | ##### qtmodules { "module", "module", ...} 112 | 113 | Specify which module you want to use. The available modules are (for the moment) 114 | 115 | * [core](http://doc.qt.io/qt-5/qtcore-index.html) 116 | * [gui](http://doc.qt.io/qt-5/qtgui-index.html) 117 | * [multimedia](http://doc.qt.io/qt-5/qtmultimedia-index.html) 118 | * [network](http://doc.qt.io/qt-5/qtnetwork-index.html) 119 | * [opengl](http://doc.qt.io/qt-5/qtopengl-index.html) 120 | * [positioning](http://doc.qt.io/qt-5/qtpositioning-index.html) 121 | * [printsupport](http://doc.qt.io/qt-5/qtprintsupport-index.html) 122 | * [qml](http://doc.qt.io/qt-5/qtqml-index.html) 123 | * [quick](http://doc.qt.io/qt-5/qtquick-index.html) 124 | * [sensors](http://doc.qt.io/qt-5/qtsensors-index.html) 125 | * [sql](http://doc.qt.io/qt-5/qtsql-index.html) 126 | * [svg](http://doc.qt.io/qt-5/qtsvg-index.html) 127 | * [testlib](http://doc.qt.io/qt-5/qttest-index.html) 128 | * [websockets](http://doc.qt.io/qt-5/qtwebsockets-index.html) 129 | * [widgets](http://doc.qt.io/qt-5/qtwidgets-index.html) 130 | * [xml](http://doc.qt.io/qt-5/qtxml-index.html) 131 | 132 | Using a module will add its include folder, and link the correct librar(y/ies) 133 | The list of module can be customized. See the Examples section for more information. 134 | 135 | ##### qtgenerateddir "path" 136 | 137 | The optional path where Qt generated file are created. If omitted, those files 138 | are generated in the objdir. 139 | 140 | ##### qtmocargs { "arg", "arg", ... } 141 | 142 | An optional list of arguments that will be sent to the Qt moc tool. Each argument will be encased 143 | in double quotes, e.g. `qtmocargs { "foo", "bar" }` will appear as `"foo" "bar"` in the command line. 144 | 145 | ##### qtuicargs { "arg", "arg", ... } 146 | 147 | An optional list of arguments that will be sent to the Qt uic tool. Each argument will be encased 148 | in double quotes, e.g. `qtuicargs { "foo", "bar" }` will appear as `"foo" "bar"` in the command line. 149 | 150 | ##### qtrccargs { "arg", "arg", ... } 151 | 152 | An optional list of arguments that will be sent to the Qt rcc tool. Each argument will be encased 153 | in double quotes, e.g. `qtrccargs { "foo", "bar" }` will appear as `"foo" "bar"` in the command line. 154 | 155 | ##### qtlreleaseargs { "arg", "arg", ... } 156 | 157 | An optional list of arguments that will be sent to the Qt lrelease tool. Each argument will be encased 158 | in double quotes, e.g. `qtlreleaseargs { "foo", "bar" }` will appear as `"foo" "bar"` in the command line. 159 | 160 | ##### qtqmgenerateddir "path" 161 | 162 | The optional path, relative to the current script, where the qm files generated 163 | by Qt will be created. If omitted, the default behavior is to generate those files in the target directory. 164 | 165 | ##### qtcommandlinesizelimit ( integer ) 166 | 167 | This option can be used to tell Qt tools to store their command line arguments 168 | into files, if the size of that command line exceed the given limit. 169 | 170 | This is used to go around a limitation of Windows. On older Windows operating 171 | system, command lines can't exceed a fixed size (see 172 | [this Microsoft support page](https://support.microsoft.com/en-us/help/830473/command-prompt-cmd--exe-command-line-string-limitation)) 173 | 174 | If this command is not used, the addon will use a limit of 2047 character on 175 | Windows only. If you're on more recent Windows, use this command to raise the limit. Also, 176 | if this command is used, it will apply the limit to the current configuration, so you can 177 | force this behavior on all operating systems if needed. 178 | 179 | 180 | Examples 181 | ======== 182 | 183 | Basic Use 184 | --------- 185 | 186 | Here is a small example of how to use the addon : 187 | 188 | 189 | ```lua 190 | -- 191 | -- Include the Qt functionalities and create a shortcut 192 | -- 193 | require( "premake-qt/qt.lua" ) 194 | local qt = premake.extensions.qt 195 | 196 | -- main solution 197 | solution "TestQt" 198 | 199 | -- 200 | -- setup your solution's configuration here ... 201 | -- 202 | 203 | -- main project 204 | project "TestQt" 205 | 206 | -- 207 | -- setup your project's configuration here ... 208 | -- 209 | 210 | -- add the files 211 | files { "**.h", "**.cpp", "**.ts", "**.ui", "**.qrc" } 212 | 213 | 214 | -- 215 | -- Enable Qt for this project. 216 | -- 217 | qt.enable() 218 | 219 | -- 220 | -- Include Qt module directories as external to avoid possible warnings. 221 | -- 222 | qtuseexternalinclude ( true ) 223 | 224 | -- 225 | -- Setup the Qt path. This apply to the current configuration, so 226 | -- if you handle x32 and x64, you can specify a different path 227 | -- for both configurations. 228 | -- 229 | -- Note that if this is ommited, the addon will try to look for the 230 | -- QTDIR environment variable. If it's not found, then the script 231 | -- will return an error since it won't be able to find the path 232 | -- to your Qt installation. 233 | -- 234 | qtpath "C:/Qt/5.1" 235 | 236 | -- 237 | -- Setup which Qt modules will be used. This also apply to the 238 | -- current configuration, so can you choose to deactivate a module 239 | -- for a specific configuration. 240 | -- 241 | qtmodules { "core", "gui", "widgets", "opengl" } 242 | 243 | -- 244 | -- Setup the prefix of the Qt libraries. Usually it's Qt4 for Qt 4.x 245 | -- versions and Qt5 for Qt 5.x ones. Again, this apply to the current 246 | -- configuration. So if you want to have a configuration which uses 247 | -- Qt4 and one that uses Qt5, you can do it. 248 | -- 249 | qtprefix "Qt5" 250 | 251 | -- 252 | -- Setup the suffix for the Qt libraries. The debug versions of the 253 | -- Qt libraries usually have a "d" suffix. If you compiled your own 254 | -- version, you could also have suffixes for x64 libraries, etc. 255 | -- 256 | configuration { "Debug" } 257 | qtsuffix "d" 258 | configuration { } 259 | ``` 260 | 261 | Adding modules 262 | -------------- 263 | 264 | You can add modules to the addon like this : 265 | 266 | ```lua 267 | -- 268 | -- Include the Qt functionalities and create a shortcut 269 | -- 270 | require( "premake-qt/qt.lua" ) 271 | local qt = premake.extensions.qt 272 | 273 | -- 274 | -- modules is a table where the key is a string identifying the module (the 275 | -- strings that you use with the `qtmodules` command) 276 | -- the value is an object containing the following members : 277 | -- * name : The name of the module. It's the part which appears 278 | -- in the lib and dll names without the suffixes and prefixes. 279 | -- For instance for core, it's "Core". 280 | -- * include : This is the include folder for the module, relative to the base 281 | -- Qt include path. For instance for core, it's "QtCore" 282 | -- * links : This an optional list of links to add. For instance for the opengl 283 | -- module, we need to link against OpenGL lib, so it's { "OpenGL32" } 284 | -- * defines : Specify one or more defines to add when using the module. It can 285 | -- be a string or a list of string. For instance { "QT_GUI_LIB" } for gui module. 286 | -- 287 | -- Here, we add support for xml (well, it's already supported, but it's for the example's sake :) 288 | -- 289 | qt.modules["xml"] = { 290 | name = "Xml", 291 | include = "QtXml", 292 | defines = "QT_XML_LIB" 293 | } 294 | 295 | -- 296 | -- then you can just use the newly added module like the other ones, the addon 297 | -- will take care of linking the library, adding the suffixes, etc. 298 | -- 299 | qdtmodules { "core", "xml" } 300 | ``` 301 | -------------------------------------------------------------------------------- /qt.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | -- 4 | -- always include _preload so that the module works even when not embedded. 5 | -- 6 | if premake.extensions == nil or premake.extensions.qt == nil then 7 | include ( "_preload.lua" ) 8 | end 9 | 10 | -- 11 | -- define the qt extension 12 | -- 13 | premake.extensions.qt = { 14 | 15 | -- 16 | -- these are private, do not touch 17 | -- 18 | enabled = false, 19 | defaultpath = os.getenv("QTDIR") or os.getenv("QT_DIR"), 20 | major_version = "5" 21 | } 22 | 23 | -- include list of modules 24 | -- note: ideally, I would just include the correct version in premake.extensions.qt.enable but for some 25 | -- reason when doing it, it fails with a "cannot open file..." although the working dir and filename 26 | -- are exactly the same as when done from here... so until I find out why, load both. 27 | premake.extensions.qt.modules = {} 28 | include ( "qtmodules.qt5.lua" ) 29 | include ( "qtmodules.qt6.lua" ) 30 | 31 | 32 | -- 33 | -- Enable Qt for a project. Be carefull, although this is a method, it will enable Qt 34 | -- functionalities only in the current configuration. 35 | -- 36 | -- @param major_version 37 | -- This is the major Qt version number used, passed as a string. If omitted, defaults to "5". 38 | -- 39 | function premake.extensions.qt.enable(major_version) 40 | 41 | local qt = premake.extensions.qt 42 | 43 | -- store the major version if it was provided 44 | if major_version ~= nil then 45 | if qt.modules["qt" .. major_version] ~= nil then 46 | qt.major_version = major_version 47 | else 48 | printf("No modules file found for version \"%s\". Fallback to module files for version \"5\"", major_version) 49 | end 50 | end 51 | 52 | -- validate it 53 | 54 | -- enable Qt for the current config 55 | qtenabled ( true ) 56 | 57 | -- setup our overrides if not already done 58 | if qt.enabled == false then 59 | qt.enabled = true 60 | premake.override(premake.oven, "bakeConfig", qt.customBakeConfig) 61 | premake.override(premake.fileconfig, "addconfig", qt.customAddFileConfig) 62 | end 63 | 64 | end 65 | 66 | 67 | -- 68 | -- Get the include, lib and bin paths 69 | -- 70 | function premake.extensions.qt.getPaths(cfg) 71 | -- get the main path 72 | local qtpath = cfg.qtpath or premake.extensions.qt.defaultpath 73 | 74 | -- return the paths 75 | return cfg.qtincludepath or (qtpath and qtpath .. "/include"), 76 | cfg.qtlibpath or (qtpath and qtpath .. "/lib"), 77 | cfg.qtbinpath or (qtpath and qtpath .. "/bin") 78 | end 79 | 80 | 81 | -- 82 | -- Get the Qt version number 83 | -- 84 | -- @param cfg 85 | -- The input configuration 86 | -- @param includepath 87 | -- The Qt include path 88 | -- @return 89 | -- The Qt version string 90 | -- 91 | function premake.extensions.qt.getVersion(cfg, includepath) 92 | -- get the version number 93 | local qtversion = cfg.qtversion 94 | 95 | -- if we haven't cached the version and/or the project didn't specify one... 96 | -- try and work it out 97 | if qtversion == nil then 98 | -- pre-5.6 stored the version string in qglobal.h ; post-5.6 in qconfig.h 99 | local qtheaderpaths = { includepath .. "/QtCore/qconfig.h", includepath .. "/QtCore/qglobal.h" } 100 | for _, headerpath in ipairs(qtheaderpaths) do 101 | 102 | -- scan the file if it exists 103 | local file = io.open(headerpath) 104 | if file ~= nil then 105 | 106 | -- scan to find 'QT_VERSION_STR' and extract the version number 107 | for line in file:lines() do 108 | if line:find("QT_VERSION_STR") then 109 | qtversion = line:sub(line:find("\"")+1, line:find("\"[^\"]*$")-1) 110 | break 111 | end 112 | end 113 | 114 | io.close(file) 115 | end 116 | 117 | -- if we found the version, break out of the loop 118 | if qtversion ~=nil then 119 | break 120 | end 121 | end 122 | end 123 | 124 | return qtversion 125 | end 126 | 127 | 128 | -- 129 | -- A small function which will get the generated directory for a given config. 130 | -- If objdir was specified, it will be used. Else, it's the project's location + 131 | -- obj + configuration + platform 132 | -- 133 | -- @param cfg 134 | -- The input configuration 135 | -- 136 | function premake.extensions.qt.getGeneratedDir(cfg) 137 | 138 | -- check if the user specified a qtgenerateddir 139 | if cfg.qtgenerateddir ~= nil then 140 | return cfg.qtgenerateddir 141 | end 142 | 143 | -- try the objdir, if it's already baked 144 | if cfg.objdir ~= nil then 145 | return cfg.objdir 146 | end 147 | 148 | -- last resort, revert to the default obj path used by premake. 149 | -- note : this is a bit hacky, but there is no easy "getobjdir(cfg)" method in 150 | -- premake, thus this piece of code 151 | dir = path.join(cfg.project.location, "obj") 152 | if cfg.platform then 153 | dir = path.join(dir, cfg.platform) 154 | end 155 | dir = path.join(dir, cfg.buildcfg) 156 | return path.getabsolute(dir) 157 | 158 | end 159 | 160 | 161 | -- 162 | -- Override the premake.oven.bakeConfig method to configure the configuration object 163 | -- with the Qt module (e.g. add the include directories, the links, etc.) 164 | -- 165 | -- @param base 166 | -- The original bakeConfig method. 167 | -- @param wks 168 | -- The current workspace. 169 | -- @param prj 170 | -- The current project. 171 | -- @param buildcfg 172 | -- The current configuration. 173 | -- @param platform 174 | -- The current platform. 175 | -- @param extraFilters 176 | -- Optional additional filters. 177 | -- @return 178 | -- The configuration object. 179 | -- 180 | function premake.extensions.qt.customBakeConfig(base, wks, prj, buildcfg, platform, extraFilters) 181 | 182 | local qt = premake.extensions.qt 183 | local modules = qt.modules["qt" .. qt.major_version] 184 | 185 | -- bake 186 | local config = base(wks, prj, buildcfg, platform, extraFilters) 187 | 188 | -- do nothing if qt is not enabled for this config 189 | if config.qtenabled ~= true then 190 | return config 191 | end 192 | 193 | -- get the needed pathes 194 | local qtinclude, qtlib, qtbin = qt.getPaths(config) 195 | if qtinclude == nil or qtlib == nil or qtbin == nil then 196 | error( 197 | "Some Qt paths were not found. Ensure that you set the Qt path using\n" .. 198 | "either 'qtpath' in your project configuration or using the QTDIR or\n" .. 199 | "QT_DIR environment variable. You can also use the 'qtincludepath',\n" .. 200 | "'qtlibpath' and 'qtbinpath' individually." 201 | ) 202 | end 203 | 204 | -- bake paths in the config (in case they were retrieved from the environment variable, they 205 | -- will not be in the config objects, and we need them in the other baking methods) 206 | config.qtincludepath = qtinclude 207 | config.qtlibpath = qtlib 208 | config.qtbinpath = qtbin 209 | 210 | -- add the includes and libraries directories 211 | local includedirs = iif(config.qtuseexternalinclude, config.externalincludedirs, config.includedirs) 212 | table.insert(includedirs, qtinclude) 213 | table.insert(config.libdirs, qtlib) 214 | 215 | -- get the prefix and suffix 216 | local prefix = config.qtprefix or "Qt" .. qt.major_version 217 | local suffix = config.qtsuffix or "" 218 | 219 | -- platform specifics 220 | if _TARGET_OS == "macosx" then 221 | 222 | -- -F set where the frameworks are located, and it's needed for header and libs 223 | table.insert(config.buildoptions, "-F" .. qtlib) 224 | table.insert(config.linkoptions, "-F" .. qtlib) 225 | 226 | -- for dynamic libs resolution 227 | table.insert(config.linkoptions, "-Wl,-rpath," .. qtlib) 228 | 229 | elseif _TARGET_OS == "linux" then 230 | 231 | -- for dynamic libs resolution 232 | table.insert(config.linkoptions, "-Wl,-rpath," .. qtlib) 233 | 234 | elseif _TARGET_OS == "windows" then 235 | 236 | -- handle the qtmain lib 237 | if config.qtmain == true then 238 | if qt.major_version == "6" then 239 | printf("\"qtmain\" function is deprecated in Qt6, please use the \"entrypoint\" module instead.") 240 | table.insert(config.qtmodules, "entrypoint") 241 | else 242 | table.insert(config.links, "qtmain" .. suffix .. ".lib") 243 | end 244 | end 245 | 246 | end 247 | 248 | -- add the modules 249 | for _, modulename in ipairs(config.qtmodules) do 250 | 251 | -- private modules are indicated by modulename-private 252 | -- this will implicitly add the associated public module and the private module header path 253 | if modulename:endswith("-private") then 254 | 255 | -- we need the version for the private header path 256 | config.qtversion = qt.getVersion(config, qtinclude) 257 | if config.qtversion == nil then 258 | error( 259 | "Cannot add module \"" .. modulename .. "\": unable to determine Qt Version.\n" .. 260 | "You can explicitly set the version number using 'qtversion' in your project\n" .. 261 | "configuration." 262 | ) 263 | end 264 | 265 | -- truncate the "-private" 266 | modulename = modulename:sub(1, -9) 267 | 268 | -- add the private part of the module 269 | local module = modules[modulename] 270 | if module ~= nil then 271 | local privatepath = path.join(qt.getIncludeDir(config, module), config.qtversion) 272 | local includedirs = iif(config.qtuseexternalinclude, config.externalincludedirs, config.includedirs) 273 | table.insert(includedirs, privatepath) 274 | table.insert(includedirs, path.join(privatepath , module.include)) 275 | end 276 | 277 | end 278 | 279 | -- add the public part of the module 280 | if modules[modulename] ~= nil then 281 | 282 | local module = modules[modulename] 283 | local libname = prefix .. module.name .. suffix 284 | 285 | -- configure the module 286 | local includedirs = iif(config.qtuseexternalinclude, config.externalincludedirs, config.includedirs) 287 | table.insert(includedirs, qt.getIncludeDir(config, module)) 288 | 289 | if module.defines ~= nil then 290 | qt.mergeDefines(config, module.defines) 291 | end 292 | 293 | if config.kind ~= "StaticLib" then 294 | if _TARGET_OS == "macosx" then 295 | table.insert(config.links, path.join(qtlib, module.include .. ".framework")) 296 | else 297 | table.insert(config.links, libname) 298 | end 299 | 300 | -- add additional links 301 | if module.links ~= nil then 302 | for _, additionallink in ipairs(module.links) do 303 | table.insert(config.links, additionallink) 304 | end 305 | end 306 | end 307 | else 308 | printf("Unknown module \"%s\" used.", modulename) 309 | end 310 | end 311 | 312 | -- return the modified config 313 | return config 314 | 315 | end 316 | 317 | 318 | -- 319 | -- Helper function used to merge args coming from file configs and from the project config. 320 | -- 321 | -- @param ... 322 | -- List of tables to merge. 323 | -- @return 324 | -- A list (indexed from 1 to N) of the arguments that were stored in the input tables. 325 | -- 326 | function premake.extensions.qt.combineArgs(...) 327 | local result = {} 328 | for _, t in ipairs({...}) do 329 | if type(t) == "table" then 330 | for _, v in ipairs(t) do 331 | table.insert(result, v) 332 | end 333 | end 334 | end 335 | return result 336 | end 337 | 338 | 339 | -- 340 | -- Helper function that is used to add a custom command. 341 | -- 342 | -- @note 343 | -- This should not be needed. Using the file config's buildmessage, buildcommands, etc. 344 | -- should work. But for some reason, when doing it like this, gmake2 doesn't get the 345 | -- custom commands, even though the other generators do (at least VS ones and gmake) 346 | -- Since this workaround uses an internal Premake-core field, this helper is used to 347 | -- make future updates easier. 348 | -- 349 | -- @param fcfg 350 | -- The file config object on which we want to add the custom command. 351 | -- @param options 352 | -- Custom command options. This should be a table, with the following fields: 353 | -- - message (string) : The build message. Mandatory. 354 | -- - commands (table of strings): The build commands. Mandatory. 355 | -- - outputs (table of strings) : The output files. Mandatory. 356 | -- - inputs (table of string) : List of files on this this command depends. Optional. 357 | -- - compile (boolean) : If true, the outputs of this command will be compiled. Optional (false by default). 358 | -- 359 | function premake.extensions.qt.addCustomCommand(fcfg, options) 360 | local configset = premake.configset 361 | local field = premake.field 362 | 363 | -- mandatory stuff 364 | configset.store(fcfg._cfgset, field.get("buildmessage"), options.message) 365 | configset.store(fcfg._cfgset, field.get("buildcommands"), options.commands) 366 | configset.store(fcfg._cfgset, field.get("buildoutputs"), options.outputs) 367 | 368 | -- optional ones 369 | if options["inputs"] ~= nil and #options["inputs"] > 0 then 370 | configset.store(fcfg._cfgset, field.get("buildinputs"), options["inputs"]) 371 | end 372 | if options["compile"] == true then 373 | configset.store(fcfg._cfgset, field.get("compilebuildoutputs"), true) 374 | end 375 | end 376 | 377 | 378 | -- 379 | -- Override the base premake.fileconfig.addconfig method in order to add our 380 | -- custom build rules for special Qt files. 381 | -- 382 | -- @param base 383 | -- The base method that we must call. 384 | -- @param fcfg 385 | -- The file configuration object. 386 | -- @param cfg 387 | -- The current configuration that we're adding to the file configuration. 388 | -- 389 | function premake.extensions.qt.customAddFileConfig(base, fcfg, cfg) 390 | 391 | -- call the base method to add the file config 392 | base(fcfg, cfg) 393 | 394 | -- do nothing else if Qt is not enabled 395 | if cfg.qtenabled ~= true then 396 | return 397 | end 398 | 399 | -- get the current config 400 | local config = premake.fileconfig.getconfig(fcfg, cfg) 401 | 402 | -- now filter the files, and depending on their type, add our 403 | -- custom build rules 404 | 405 | local qt = premake.extensions.qt 406 | 407 | -- ui files 408 | if qt.isUI(config.abspath) then 409 | qt.addUICustomBuildRule(config, cfg) 410 | 411 | -- add directory in which the UI headers are generated to the config, if not already. 412 | local includedir = qt.getGeneratedDir(cfg) 413 | if table.contains(cfg.includedirs, includedir) == false then 414 | table.insert(cfg.includedirs, includedir) 415 | end 416 | 417 | -- resource files 418 | elseif qt.isQRC(config.abspath) then 419 | qt.addQRCCustomBuildRule(config, cfg) 420 | 421 | -- translation files 422 | elseif qt.isTS(config.abspath) then 423 | qt.addTSCustomBuildRule(config, cfg) 424 | 425 | -- moc files 426 | elseif qt.needMOC(config.abspath) then 427 | qt.addMOCCustomBuildRule(config, cfg) 428 | 429 | end 430 | 431 | -- the cpp files generated by the qrc tool can't use precompiled header, so 432 | -- if we have pch and the file is a Qt generated one, check if it's generated 433 | -- by qrc to disable pch for it. 434 | if cfg.pchheader and config.abspath:find(qt.getGeneratedDir(cfg), 1, true) then 435 | 436 | -- the generated dir path might contain special pattern character, so escape them 437 | local pattern = path.wildcards(qt.getGeneratedDir(cfg)) 438 | 439 | -- if it's a qrc generated file, disable pch 440 | if config.abspath:find(pattern .. "/qrc_.+%.cpp") then 441 | config.flags.NoPCH = true 442 | end 443 | end 444 | 445 | end 446 | 447 | 448 | -- 449 | -- Checks if a file is a ui file. 450 | -- 451 | -- @param filename 452 | -- The file name to check. 453 | -- @return 454 | -- true if the file needs to be run through the uic tool, false if not. 455 | -- 456 | function premake.extensions.qt.isUI(filename) 457 | return path.hasextension(filename, { ".ui" }) 458 | end 459 | 460 | 461 | -- 462 | -- Adds the custom build for ui files. 463 | -- 464 | -- @param fcfg 465 | -- The config for a single file. 466 | -- @param cfg 467 | -- The config of the project ? 468 | -- 469 | function premake.extensions.qt.addUICustomBuildRule(fcfg, cfg) 470 | 471 | local qt = premake.extensions.qt 472 | 473 | -- get the output file 474 | local output = qt.getGeneratedDir(cfg) .. "/ui_" .. fcfg.basename .. ".h" 475 | 476 | -- build the command 477 | local command = "\"" .. fcfg.config.qtbinpath .. "/uic\" -o \"" .. path.getrelative(fcfg.project.location, output) .. "\" \"" .. fcfg.relpath.. "\"" 478 | 479 | -- if we have custom commands, add them 480 | table.foreachi(qt.combineArgs(fcfg.config.qtuicargs, fcfg.qtuicargs), function (arg) 481 | command = command .. " \"" .. arg .. "\"" 482 | end) 483 | 484 | -- add the custom build rule 485 | qt.addCustomCommand(fcfg, { 486 | message = "Running uic on %{file.name}", 487 | commands = { command }, 488 | outputs = { output }, 489 | inputs = { fcfg.abspath } 490 | }) 491 | end 492 | 493 | 494 | -- 495 | -- Checks if a file is a qrc file. 496 | -- 497 | -- @param filename 498 | -- The file name to check. 499 | -- @return 500 | -- true if the file needs to be run through the rcc tool, false if not. 501 | -- 502 | function premake.extensions.qt.isQRC(filename) 503 | return path.hasextension(filename, { ".qrc" }) 504 | end 505 | 506 | 507 | -- 508 | -- Adds the custom build for qrc files. 509 | -- 510 | -- @param fcfg 511 | -- The config for a single file. 512 | -- @param cfg 513 | -- The config of the project ? 514 | -- 515 | function premake.extensions.qt.addQRCCustomBuildRule(fcfg, cfg) 516 | 517 | local qt = premake.extensions.qt 518 | 519 | -- get the input and output files 520 | local output = qt.getGeneratedDir(cfg) .. "/qrc_" .. fcfg.basename .. ".cpp" 521 | 522 | -- build the command 523 | local command = "\"" .. fcfg.config.qtbinpath .. "/rcc\" -name \"" .. fcfg.basename .. "\" -no-compress \"" .. fcfg.relpath .. "\" -o \"" .. path.getrelative(fcfg.project.location, output) .. "\"" 524 | 525 | -- if we have custom commands, add them 526 | table.foreachi(qt.combineArgs(fcfg.config.qtrccargs, fcfg.qtrccargs), function (arg) 527 | command = command .. " \"" .. arg .. "\"" 528 | end) 529 | 530 | -- get the files embedded on the qrc, to add them as input dependencies : 531 | -- if we edit a .qml embedded in the qrc, we want the qrc to re-build whenever 532 | -- we edit the qml file 533 | local inputs = qt.getQRCDependencies(fcfg) 534 | 535 | -- add the custom build rule 536 | qt.addCustomCommand(fcfg, { 537 | message = "Running qrc on %{file.name}", 538 | commands = { command }, 539 | outputs = { output }, 540 | inputs = inputs, 541 | compile = true 542 | }) 543 | end 544 | 545 | 546 | -- 547 | -- Get the files referenced by a qrc file. 548 | -- 549 | -- @param fcfg 550 | -- The configuration of the file 551 | -- @return 552 | -- The list of project relative file names of the dependencies 553 | -- 554 | function premake.extensions.qt.getQRCDependencies(fcfg) 555 | local dependencies = {} 556 | local file = io.open(fcfg.abspath) 557 | 558 | -- ensure the file was correctly opened 559 | if file ~= nil then 560 | local qrcdirectory = path.getdirectory(fcfg.abspath) 561 | 562 | -- parse the qrc file to find the files it will embed 563 | for line in file:lines() do 564 | -- try to find the entries 565 | local match = string.match(line, "(.+)") 566 | if match == nil then 567 | match = string.match(line, "]*>(.+)") 568 | end 569 | 570 | -- if we have one, compute the path of the file, and add it to the dependencies 571 | -- NOTE: the QRC files are relative to the folder containing the qrc file. 572 | if match ~= nil then 573 | table.insert(dependencies, path.join(qrcdirectory, match)) 574 | end 575 | end 576 | 577 | -- close the qrc file 578 | io.close(file) 579 | end 580 | 581 | return dependencies 582 | end 583 | 584 | 585 | -- 586 | -- Checks if a file is a ts file. 587 | -- 588 | -- @param filename 589 | -- The file name to check. 590 | -- @return 591 | -- true if the file needs to be run through the lrelease tool, false if not. 592 | -- 593 | function premake.extensions.qt.isTS(filename) 594 | return path.hasextension(filename, { ".ts" }) 595 | end 596 | 597 | 598 | -- 599 | -- Adds the custom build for a ts file. 600 | -- 601 | -- @param fcfg 602 | -- The config for a single file. 603 | -- @param cfg 604 | -- The config of the project ? 605 | -- 606 | function premake.extensions.qt.addTSCustomBuildRule(fcfg, cfg) 607 | local qt = premake.extensions.qt 608 | 609 | -- create the output file name 610 | local qtqmgenerateddir = fcfg.qtqmgenerateddir or fcfg.config.qtqmgenerateddir 611 | local outputdir = qtqmgenerateddir or cfg.targetdir 612 | local output = path.join(outputdir, fcfg.basename .. ".qm") 613 | 614 | -- create the command 615 | local command = "\"" .. fcfg.config.qtbinpath .. "/lrelease\" \"" .. fcfg.relpath .. "\"" 616 | command = command .. " -qm \"" .. path.getrelative(fcfg.project.location, output) .. "\"" 617 | 618 | -- add additional args 619 | table.foreachi(qt.combineArgs(cfg.qtlreleaseargs, fcfg.qtlreleaseargs), function (arg) 620 | command = command .. " \"" .. arg .. "\"" 621 | end) 622 | 623 | -- add the custom build rule 624 | qt.addCustomCommand(fcfg, { 625 | message = "Running lrelease on %{file.name}", 626 | commands = { command }, 627 | outputs = { output } 628 | }) 629 | end 630 | 631 | 632 | -- 633 | -- Checks if a file needs moc'ing. 634 | -- 635 | -- @param filename 636 | -- The file name to check. 637 | -- @return 638 | -- true if the header needs to be run through the moc tool, false if not. 639 | -- 640 | function premake.extensions.qt.needMOC(filename) 641 | 642 | local needmoc = false 643 | 644 | -- only handle headers 645 | if path.iscppheader(filename) then 646 | 647 | -- open the file 648 | local file = io.open(filename) 649 | if file ~= nil then 650 | 651 | -- scan it to find 'Q_OBJECT' or 'Q_GADGET' 652 | for line in file:lines() do 653 | if line:find("^%s*Q_OBJECT%f[^%w_]") or line:find("^%s*Q_GADGET%f[^%w_]") then 654 | needmoc = true 655 | break 656 | end 657 | end 658 | 659 | io.close(file) 660 | end 661 | end 662 | 663 | return needmoc 664 | end 665 | 666 | 667 | -- 668 | -- Adds the custom build for a moc'able file. 669 | -- 670 | -- @param fcfg 671 | -- The config for a single file. 672 | -- @param cfg 673 | -- The config of the project ? 674 | -- 675 | function premake.extensions.qt.addMOCCustomBuildRule(fcfg, cfg) 676 | 677 | local qt = premake.extensions.qt 678 | 679 | -- get the project's location (to make paths relative to it) 680 | local projectloc = fcfg.project.location 681 | 682 | -- create the output file name 683 | local output = qt.getGeneratedDir(cfg) .. "/moc_" .. fcfg.basename .. ".cpp" 684 | 685 | -- create the command 686 | local command = "\"" .. fcfg.config.qtbinpath .. "/moc\" \"" .. fcfg.relpath .. "\"" 687 | command = command .. " -o \"" .. path.getrelative(projectloc, output) .. "\"" 688 | 689 | -- if we have a precompiled header, prepend it 690 | if fcfg.config.pchheader then 691 | command = command .. " -b \"" .. fcfg.config.pchheader .. "\"" 692 | end 693 | 694 | -- now create the arguments 695 | local arguments = "" 696 | 697 | -- append the defines to the arguments 698 | table.foreachi(qt.combineArgs(fcfg.config.defines, fcfg.defines), function (define) 699 | arguments = arguments .. " -D" .. define 700 | end) 701 | 702 | -- append the include directories to the arguments 703 | table.foreachi(qt.combineArgs(fcfg.config.includedirs, fcfg.includedirs), function (include) 704 | arguments = arguments .. " -I\"" .. path.getrelative(projectloc, include) .. "\"" 705 | end) 706 | 707 | -- if we have custom commands, add them 708 | table.foreachi(qt.combineArgs(fcfg.config.qtmocargs, fcfg.qtmocargs), function (arg) 709 | arguments = arguments .. " \"" .. arg .. "\"" 710 | end) 711 | 712 | -- handle the command line size limit 713 | command = qt.handleCommandLineSizeLimit(cfg, fcfg, command, arguments) 714 | 715 | -- add the custom build rule 716 | qt.addCustomCommand(fcfg, { 717 | message = "Running moc on %{file.name}", 718 | commands = { command }, 719 | outputs = { output }, 720 | compile = true 721 | }) 722 | end 723 | 724 | 725 | -- 726 | -- Checks if the command line will exceed the given size limit, and will output 727 | -- the arguments to a file if so. The updated command is returned 728 | -- 729 | -- @param cfg 730 | -- The configuration object. 731 | -- @param fcfg 732 | -- The file configuration object. 733 | -- @param command 734 | -- The command. 735 | -- @param arguments 736 | -- The arguments. 737 | -- @return 738 | -- The updated command. 739 | -- 740 | function premake.extensions.qt.handleCommandLineSizeLimit(cfg, fcfg, command, arguments) 741 | 742 | -- check if we need to output to a file 743 | local limit = fcfg.config.qtcommandlinesizelimit or iif(_TARGET_OS == "windows", 2047, nil) 744 | if limit ~= nil and string.len(command) + string.len(arguments) + 1 > limit then 745 | local qt = premake.extensions.qt 746 | 747 | -- create the argument file name 748 | local filename = qt.getGeneratedDir(cfg) .. "/moc_" .. fcfg.basename .. ".args" 749 | 750 | -- output the arguments to it 751 | local file = io.open(filename, "w") 752 | file:write(arguments) 753 | io.close(file) 754 | 755 | -- update the command to load this file 756 | return command .. " @\"" .. filename .. "\"" 757 | end 758 | 759 | -- update the command to include the arguments 760 | return command .. " " .. arguments 761 | 762 | end 763 | 764 | 765 | -- 766 | -- Merge defines into the configuration, taking care of not adding the 767 | -- same define twice. 768 | -- 769 | -- @param config 770 | -- The configuration object. 771 | -- @param defines 772 | -- The defines to add. 773 | -- 774 | function premake.extensions.qt.mergeDefines(config, defines) 775 | 776 | -- a function which checks if a value is contained in a table. 777 | local contains = function (t, v) 778 | for _, d in ipairs(t) do 779 | if d == v then 780 | return true 781 | end 782 | end 783 | return false 784 | end 785 | 786 | -- ensure defines is a table 787 | if type(defines) ~= "table" then 788 | defines = { defines } 789 | end 790 | 791 | -- add each defines 792 | for _, define in ipairs(defines) do 793 | if contains(config.defines, define) == false then 794 | table.insert(config.defines, define) 795 | end 796 | end 797 | 798 | end 799 | 800 | 801 | -- 802 | -- Get the include dir for the given module. 803 | -- 804 | -- @param config 805 | -- The current config. 806 | -- @param module 807 | -- The module. 808 | -- @return 809 | -- The include dir. 810 | -- 811 | function premake.extensions.qt.getIncludeDir(config, module) 812 | 813 | if _TARGET_OS == "macosx" then 814 | return path.join(config.qtlibpath, module.include .. ".framework", "Headers") 815 | else 816 | return path.join(config.qtincludepath, module.include) 817 | end 818 | 819 | end 820 | --------------------------------------------------------------------------------