How to make Qt automatically find files to be MOC'd - qt

I am modifying some existing projects that uses QT (version 5.10). I am updating them to use better, more concise msbuild syntax (Target Visual Studio 2015) on windows.
One project has about 170 header files, of which about 135 header files need to be run through MOC.exe.
Therefore I wrote a custom target to send 135 files to moc.exe. But the msbuild syntax to tell Moc which files to process is quite long.
i.e.
<QtMocs Include="A.h;
B.h;
C.h;
D.h;
etc...
I tried sending ALL of the header files through to moc.exe. But if a header file doesn't have Q_OBJECT, then moc.exe emits a warning about not needing to moc the header file. And to add insult to injury it still emits a cpp file, even though nothing needed to be moc'd.
So I'd like to write a nice short (one line?) concise way to tell QT to moc only the headers that are needed.
Is this possible?

So after two days with no response, I decided to write my own solution, which works really well. I wrote a custom task for MSBuild. It takes an array of ProjectItem's that is supposed to point to all the header files in your project. Then for each file in the array, it opens the files, searches for Q_OBJECT and if found saves off the Item into an output array. That output array is then queried later on and sent to moc.exe.
<!-- Task to automatically discover header files that need to be run through QT's MOC.exe compiler.
It does this by examing each file and checking if 'Q_OBJECT' is in the file. -->
<UsingTask TaskName="FindFilesForQtMoc" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
<ParameterGroup>
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<MocFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />
</ParameterGroup>
<Task>
<Using Namespace="System" />
<Using Namespace="System.IO" />
<Using Namespace="System.Diagnostics" />
<Code Type="Fragment" Language="cs">
<![CDATA[
var result = new List<Microsoft.Build.Framework.ITaskItem>();
foreach(var item in Files)
{
String filePath = item.GetMetadata("FullPath");
var content = File.ReadAllText(filePath);
if (content.Contains("Q_OBJECT"))
{
result.Add(item);
}
}
MocFiles = result.ToArray();
]]>
</Code>
</Task>
</UsingTask>
I call the task like this:
<FindFilesForQtMoc Files="#(ClInclude)" >
<Output ItemName="FileForMoc" TaskParameter="MocFiles" />
</FindFilesForQtMoc>
<Message Text="Moc: %(FileForMoc.Identity)" />
Therefore I only have to declare all my header files in my .vcxproj like this:
<ClInclude Include="*.h" />
Which is way better than explicitly declaring each and every file that needs moc.exe.

Related

Qt - Add files to project

I'm making an application part of which is reading from an XML which stores some preferences. However, whenever I build the project, all the sources get copied but the preferences file does not! I have added the following to the .pro file -
RESOURCES += rsc.qrc
And my rsc.qrc contains
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>data/preferences.xml</file>
<file>data/gamedata.xml</file>
</qresource>
</RCC>
Now whenever I try to open preferences.xml
QFile preferences(":/data/preferences.xml");
if(!preferences.exists()){
preferences.open(QFile::WriteOnly);
preferences.write("abc");
qDebug() << "Written";
}
else {
qDebug() << "File exists";
}
Absolutely nothing gets printed and even the rest of the application stops working.
You don't use the resource part correctly in your example.
It will most likely not work because you try to write to a resource that is embedded into your executable after you have build your application. Reading is fine, but writing can't work by definition.
If you want a editable setting files, you have to distribute them along with your executable, or use a different method for reading/writing your settings like QSettings.
However using QSettings also means, that you will need to configure all your default settings in your loading function in case the values do not exist if you use the default configuration. Meaning you use registry on windows.
You have the option to force the use of a INI file format in the constructor of QSettings, this can make sense if you want to provide a default settings INI file instead of your xml files.
In case you want to store more complex data a xml file might be needed anyway, so if you want to stick with that you will need a way to copy your setting files to your build path. This can be done within your pro file with QMAKE_POST_LINK.
Example:
COPY_CMD = "$$PWD\\data\\preferences.xml $$OUT_PWD\\release\\data\\preferences.xml"
COPY_CMD = $${QMAKE_COPY} $$replace( COPY_CMD, "/", "\\" ) $$escape_expand( \\n\\t )
QMAKE_POST_LINK += $$COPY_CMD

Closure Templates generates code that does not use StringBuilder

I recently pull a project from GitHub that included a compile-soy task in its build.xml. The task uses SoyToJsSrcCompiler.jar to compile a couple of soy files into javascript. The project included the target directory so I could see that the compiled files contain code like this:
jive.fbldr.soy.attachments = function(opt_data, opt_sb) {
var output = opt_sb || new soy.StringBuilder();
output.append('<div class="fbldr-attachments"><div class="fbldr-attach-head"><p>Use the following form to upload file attachments and, optionally, include a variable to reference the uploaded file in the form\'s HTML source.</p><p>Multiple files may be attached, but only one at a time. Click "Finished" when all files have been attached.</p></div><div class="fbldr-attach-field"><label>Link to HTML Variable (optional) : </label></div><div class="fbldr-attach-field"><select id="fbldr-attach-link"><option value="" selected="selected">Select HTML variable...</option>');
var optionList34 = opt_data.variables;
var optionListLen34 = optionList34.length;
When I run the same task without any code changes, the resulting compiled keeps replacing opt_sb with opt_ignored and stripped out all references to soy.StringBuilder. I ran "java -jar lib/SoyToJsSrcCompiler.jar --outputPathFormat target/soy2/fbldr.soy templates/fbldr.soy" by hand instead of using the build.xml. I get the same result.
jive.fbldr.soy.attachments = function(opt_data, opt_ignored) {
var output = '<div class="fbldr-attachments"><div class="fbldr-attach-head"><p>Use the following form to upload file attachments and, optionally, include a variable to reference the uploaded file in the form\'s HTML source.</p><p>Multiple files may be attached, but only one at a time. Click "Finished" when all files have been attached.</p></div><div class="fbldr-attach-field"><label>Link to HTML Variable (optional) : </label></div><div class="fbldr-attach-field"><select id="fbldr-attach-link"><option value="" selected="selected">Select HTML variable...</option>';
var optionList4 = opt_data.variables;
var optionListLen4 = optionList4.length;
From all the Closure Templates documentation I've read, it is expected the output will use StringBuilder. I cannot figure out why my call keeps generating output that ignores the StringBuilder. Would someone happen to know what could cause this?
StringBuilder was appropriate for Internet Explorer 7 and earlier browsers. For modern browsers simple string concatenation is more efficient and Closure Templates was changed to make that mode the default mode (as an added bonus, the code is smaller). It sounds like the documentation has not been updated to reflect this change.
If for compatibility reasons your require StringBuilder you can set this option on the command-line using --codeStyle stringbuilder

Flex conditional compilation of MXML?

In Flex it is now possible to use the -define compiler option to do all sorts of cool stuff.
In my program, I am using the option such that some of my code is excluded by blocks like this:
CONFIG::FACEBOOK{
//Some code
}
And this is working well.
How do I get a similar behaviour with MXML?
I want to do the same thing, but omitting/including MXML tags in this way, not blocks of AS code.
My solution is to add some tags that could help to comment out unnecessary blocks of mxml code in certain build.
For example I want to add different buttons in Android and iOS builds:
<!-- iOS --><!--
<s:Button id="backBtn"
icon="{SHOW_LIST}"
click="navigator.popView()"/>
--><!-- /iOS -->
<!--Android-->
<s:Button id="exitBtn"
label="Exit"
click="NativeApplication.nativeApplication.exit()"/>
<!--/Android-->
Now run simple batch script which will comment out all Android specific code in the source for iOS build
PrepareForIos.cmd
#echo off
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!--Android-->" "<!-- Android --><!--"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!--/Android-->" "--><!-- /Android -->"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!-- iOS --><!--" "<!--iOS-->"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "--><!-- /iOS -->" "<!--/iOS-->"
pause
FART is a command-line tool for finding and replacing strings
Now our code looks like this and is ready to be built for iOS:
<!--iOS-->
<s:Button id="backBtn"
icon="{SHOW_LIST}"
click="navigator.popView()"/>
<!--/iOS-->
<!-- Android --><!--
<s:Button id="exitBtn"
label="Exit"
click="NativeApplication.nativeApplication.exit()"/>
--><!-- /Android -->
Inverse operation batch:
PrepareForAndroid.cmd
#echo off
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!--Android-->" "<!-- Android --><!--"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!--/Android-->" "--><!-- /Android -->"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "<!-- iOS --><!--" "<!--iOS-->"
"C:\Program Files (x86)\bin\fart.exe" -r -w -- H:\Flash\MyProject\src\* "--><!-- /iOS -->" "<!--/iOS-->"
pause
A trick I use is to create a static class that holds constants for the different builds:
package
{
public class MyAppConstants
{
CONFIG::Debug
public static const DEBUG:Boolean = true;
CONFIG::Release
public static const DEBUG:Boolean = false;
}
}
And then I use these constants in my MXML:
<namespace:component visible="{MyAppConstants.DEBUG}" includeInLayout="{MyAppConstants.DEBUG}"/>
This will make sure the component is not added to the display list and thusly not measured either. If you would only use the visible attribute the dimensions of the component are still taken into account and will therefore leave "empty" spaces.
Edited response, based on this comment:
Sorry for being slow to get back to this thread. My intention was to have some interface elements (Buttons, and the like) which were omitted in some builds and included in others. My current workaround is to simply set the visible property of the component to the compiler defined boolean constant - it's crude, but it works. Any thoughts on a better way? – Chris Kitching Sep 20 at 14:40
I think you might be able to use the deferred initialisation behaviour of flex to control which components are created and added to your parent component - it might be a little against the idea of MXML, but I think it's possible.
Here is a bit of background on manually initialising deferred components (for spark and mx components):
http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7aee.html
Flex 3
If you're using Flex 3 then you can override the createComponentsFromDescriptors() method and access the childDescriptors property to control exactly which child MXML components will be created.
The Creating deferred components article shows how you can get information about an MXML component from the descriptor. You could use this behaviour to determine which components should or shouldn't be instantiated for the current build.
Class reference for UIComponentDescriptor:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/UIComponentDescriptor.html
Flex 4
In Flex 4 it's a little less clear - all MXML components will be created from their descriptors (there isn't a childDescriptors property, just the mxmlContentFactory instance which will create all of the children).
Two options for controlling the display of MXML components might be:
Override the createDeferredContent() method and initialise the child components with the mxmlContentFactor but remove elements from the returned array before setting the mxmlContent property (which adds them to the display list).
Implement a template component that defines exactly what type of components are allowed as children, and only initialising the appropriate children for your current build type.
Here is an example of creating a template component in this way: Using IDeferredInstance in a template component.
Hopefully that gives you something to think about, and hopefully it's not too complicated :)
Original answer:
The short answer is that you can't use conditional compilation for MXML tags.
All MXML tags will be compiled into the component.
What are your goals in wanting to use conditional MXML?
Are you trying to include/exclude classes based on the compiler properties but still keep the short-hand MXML declarations? i.e. not have to define everything in actionscript.
With a bit more info we might be able to work through to an acceptable alternative :)

Conditionally including Flex libraries (SWCs) in mxmlc/compc ant tasks

I have been struggling trying to figure out how to conditionally include Flex libraries in an ant build based on a property that is set on the command line. I have tried a number of approaches with the <condition/> task, but so far have not gotten it to work. Here is where I am currently.
I have an init target that includes condition tasks like this:
<condition property="automation.libs" value="automation.qtp">
<equals arg1="${automation}" arg2="qtp" casesensitive="false" trim="true"/>
</condition>
The purpose of this task is to set a property that determines the name of the patternset to be used when declaring the implicit fileset on a mxmlc or compc task. The pattern set referenced above is defined as:
<patternset id="automation.qtp">
<include name="automation*.swc"/>
<include name="qtp.swc"/>
</patternset>
The named patternset is then referenced by the mxmlc or compc task like this:
<compc>
<compiler.include-libraries dir="${FLEX_HOME}/frameworks/libs" append="true">
<patternset refid="${automation.libs}"/>
</compiler.include-libraries>
</compc>
This doesn't appear to work. At least the SWC size does not indicate that the additional automation libraries have been compiled in. I want to be able to specify a command line property that determine which patternset to use for various types of builds.
Does anyone have any ideas about how to accomplish this? Thanks!
If you can't get <patternset> to work correctly, you might want to take a look at the <if> <then> and <else> tasks provided by ant-contrib. We ended up doing something like this:
<target name = "build">
<if>
<equals arg1="automation.qtp" arg2="true"/>
<then>
<!--
- Build with QTP support.
-->
</then>
<else>
<!--
- Build without QTP support.
-->
</else>
</if>
</target>
There is some duplication of build logic between the if and else branch, but you can factor some of that out if you wrap <mxmlc> with a macrodef.
The mxmlc task supports loading configuration files <load-config filename="path/to/flex-config.xml" />. So, generate the config xml on the fly, by combining the echoxml task and if-then-else.
<echoxml file="path/to/flex-config.xml">
<flex-config>
<compiler>
<library-path append="true">
<path-element>${lib.qtp}</path-element>
</library-path>
</compiler>
</flex-config>
</echoxml>
If your needs are more complicated, you could even generate several xml configs and <load-config ... /> them all.
Personally, I find any logic very terse and ugly to write using Ant's conditions or if-then-else, XML is not a pretty language to use for programming. Luckily, it's possible to use more flexible approach - write a script to produce the config xml, before calling mxmlc. E.g. use the script task with your favorite scripting language
<script language="javascript">
<![CDATA[
// Create your XML dynamically here.
// Write that XML to an external file.
// Later, feed that file to mxmlc using `<load-config ... />`.
]]>
</script>

ASP.NET - show application build date/info at the bottom of the screen

I have a asp.net web application which has a number of versions deployed on different customer servers inside their networks. One practice that we have is to have clients email screenshots when they have issues.
In the old asp.net 1.1 days, we could grab details of the build DLL, using reflection, and show info about the build date and numbering on the screen in a subtle location.
With .NET 2.0 and higher, the build model changed, and this mechanism no longer works. I have heard of different build systems out there, but I'm really looking for the simplest way, on the 3.5 framework, to do what this functionality did on framework 1.1.
Every time a build is performed, update the build date/time, and somehow update the build number
Be able to see the build timestamp and number, to display on the screen
be as simple to implement as possible
I chose to just use the date of the executing assembly.
The way I publish the files, this works fine.
lblVersion.Text = String.Format("Version: {0}<br>Dated: {1}",
System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
System.IO.File.GetLastWriteTime(System.Reflection.Assembly.GetExecutingAssembly().Location).ToShortDateString());
We are using .Net 2.0 and pull the version information out of the assembly. Perhaps not ideal, but we use the description to store the build date.
Assembly assembly = Assembly.GetExecutingAssembly();
string version = assembly.GetName().Version.ToString();
string buildDate = ((AssemblyDescriptionAttribute)Attribute.GetCustomAttribute(
assembly, typeof(AssemblyDescriptionAttribute))).Description;
The build process uses asminfo nant task to generate the AssemblyInfo.cs file that contains this information.
<asminfo output="Properties\AssemblyInfo.cs" language="CSharp">
<imports>
<import namespace="System" />
<import namespace="System.Reflection" />
<import namespace="System.Runtime.CompilerServices" />
<import namespace="System.Runtime.InteropServices" />
</imports>
<attributes>
<attribute type="AssemblyVersionAttribute" value="${assembly.version}" />
<attribute type="AssemblyInformationalVersionAttribute" value="${assembly.version}" />
<attribute type="AssemblyDescriptionAttribute" value="${datetime::now()}" />
...
</attributes>
</asminfo>
I'm using .NET 2.0 and 3.5 and it is able to set both the build number and build date. While the help panel says that if yet let .NET set it, it will use a random number for the revision, that isn't true, it actually puts date/time info that can be easily extracted, which is confirmed by the online docs:
http://msdn.microsoft.com/en-us/library/system.reflection.assemblyversionattribute.assemblyversionattribute.aspx
See this blog:
http://dotnetfreak.co.uk/blog/archive/2004/07/08/determining-the-build-date-of-an-assembly.aspx?CommentPosted=true#commentmessage
I want to set the build version myself but still want the automatic date/time stamp so I use something like this for the
AssemblyVersion("1.0.*")
Here is a sample function to extract the build date/time
private System.DateTime BuildDate()
{
//This ONLY works if the assembly was built using VS.NET and the assembly version attribute is set to something like the below. The asterisk (*) is the important part, as if present, VS.NET generates both the build and revision numbers automatically.
//<Assembly: AssemblyVersion("1.0.*")>
//Note for app the version is set by opening the 'My Project' file and clicking on the 'assembly information' button.
//An alternative method is to simply read the last time the file was written, using something similar to:
//Return System.IO.File.GetLastWriteTime(System.Reflection.Assembly.GetExecutingAssembly.Location)
//Build dates start from 01/01/2000
System.DateTime result = DateTime.Parse("1/1/2000");
//Retrieve the version information from the assembly from which this code is being executed
System.Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
//Add the number of days (build)
result = result.AddDays(version.Build);
//Add the number of seconds since midnight (revision) multiplied by 2
result = result.AddSeconds(version.Revision * 2);
//If we're currently in daylight saving time add an extra hour
if (TimeZone.IsDaylightSavingTime(System.DateTime.Now, TimeZone.CurrentTimeZone.GetDaylightChanges(System.DateTime.Now.Year)))
{
result = result.AddHours(1);
}
return result;
}
You can get the Assembly Build date through reflection, check this examples:
Determining Build Date the hard way
Determining the Build Date of an Assembly

Resources