Developer Blog - Inventic.eu
  • Skipper - The ORM Designer
  • VsBuilds - Parallel building
  • Pulpo - Free Skipper CLI

Category: Mac OS

Crash in QTreeWidget / QTreeView index mapping on Mac OSX 10.10 part III

So, one more attempt. Previous articles (part1, part2) mentioned possible solutions to fix crash insinde the QTreeWidget and QAccessibleTableCell.

Unfortunately, deselecting current item still doesn't fix all issues. The problem with deselection is that it's not handled correctly via QAccessibleTableCell:

If current index isn't valid, QAccessible doesn't correctly update currect QAccessibleTableCell object which caused all this evil crashes.

So there are two ways how to fix it. One is to manually set QAccessibleTableCell but I didn't find a way how to do that. The second way is to disable QAccessible for Property editor. Unfortunately it's not an easy task. In QAccessible exists method setActive:

QAccessible::setActive(false)

But this method works only with AccessibleObserver class but not with QPlatformAcessibility which handles real QAcessible::isActive result. Because of this it's necessary to update setActive method in file qacessible.cpp inside the Qt.

Original method:

</p>
<p>void QAccessible::setActive(bool active)<br />
{<br />
  for (int i = 0; i &lt; qAccessibleActivationObservers()-&gt;count() ;++i)<br />
    qAccessibleActivationObservers()-&gt;at(i)-&gt;accessibilityActiveChanged(active);<br />
}</p>
<p>

and updated version:

void QAccessible::setActive(bool active)<br />
{<br />
  #ifndef QT_NO_ACCESSIBILITY<br />
    if ( QPlatformAccessibility *pfAccessibility = platformAccessibility() )<br />
      pfAccessibility-&gt;setActive(active);<br />
  #endif</p>
<p>  for (int i = 0; i &lt; qAccessibleActivationObservers()-&gt;count() ;++i)<br />
    qAccessibleActivationObservers()-&gt;at(i)-&gt;accessibilityActiveChanged(active);<br />
}</p>
<p>

In case you will find better way how to turn off accessibility, please let me know.

But there is still one more problem. Occasionally OS X decides to switch accessible back on:

And this is probably the reason why everything works ok on older OS X but not on 10.10. Because OS X 10.10 randomly turns accessible on which causes this crash. Accessible is usually turned on when opening some modal dialog.

This explains why opening an empty dialog increased the probability to crash the application. The only solution I have found is to disable QAccessible every time the PropertyEditor is cleared up.

21 May 2015

Posted by: ludek.vodicka

Programming Qt Mac OS #Qt #crash #tree #property-editor

Crash in QTreeWidget / QTreeView index mapping on Mac OSX 10.10 part II

As mentioned in the first part of this article, the workaround with focus unfortunately didn't work. In some cases application is still crashing. So after next hours of debugging and unsuccessful consulting the problem on stack overflow I probably found a the core reason of this bug and the solution too.

2015-05-18_0850

 

The core of this problem doesn't lie in the QTreeModel, but in Qt implementation of Cocoa Accessible. The problem is that although the PropertyTree is correctly cleared, there is object QAccessibleTableCell which isn't correctly updated after

clear()

.

This means that although the PropertyTree and TreeWidget is empty, the QAccessibleTableCell object still holds m_index variable to invalid element. And when

 NSAcessibleEntryPointrAttributeNames 

is executed, m_index is translated to QTreeWidget element pointer and accessed. And this means that application completely crashes.

The solution is pretty simple. Together with property editor clear set also current index and selected index to NULL.

	propertyBrowser-&gt;clear();<br />
	propertyManagers-&gt;clear();<br />
	propertyManagers-&gt;treeWidget()-&gt;setCurrentItem(NULL);<br />
	propertyManagers-&gt;treeWidget()-&gt;setItemSelected(NULL, false);<br />

And that is it. Thanks for this your application will not crash any more (on this bug ;-) ).

 

21 May 2015

Posted by: ludek.vodicka

Qt Mac OS #qt treewidget model crash

OS X codesign failed: bundle format is ambiguous (could be app or framework)

This error can be caused by many things but I know about one more which I didn't find anywhere else ;-).

In case you compile and deploy your app by using qtmacdeploy and sign your application immediately, everything will probably works fine. The problem occurs, when you need to copy your application to different location (for example during dmg building). In such cases, this error can occur:

bundle format is ambiguous (could be app or framework)<br />

Althought codesign is executed as always, singing isn't successful:

codesign --deep --force --verbose --sign &quot;$SIGNNAME&quot; ./Skipper.app<br />
/path/Skipper.app/Contents/Frameworks/QtCore.framework: bundle format is ambiguous (could be app or framework)<br />

The problem is, that during the copy it's necessary to keep all symbolic links inside frameworks. Without this, singing will fail.

So instead of

cp -r ./Source ./Destination<br />

it's necessary to use

cp -R ./Source ./Destination<br />
05 Mar 2015

Posted by: ludek.vodicka

Mac OS #MacOs #certificate #codesign #singing

Codesign asking for credentials for on every usage

Apple OS X codesing

to fix that, it's sufficient to configure certificate to allow any application to use it without asking:

KeyChain - allow access (step 1)

KeyChain - step 2

 

External links

08 Feb 2015

Posted by: ludek.vodicka

Programming Mac OS #certificate #codesign

Mac OS - app can't be opened because the identity of the developer cannot be confirmed.

Starting with OS X 10.10 existing code signing method doesn't work. If you have application signed for 10.9 and application works without problems, with 10.10 you will get following error:

2015-02-05_1003

How to verify application sign status from command line:

codesign -dvvv /Applications/APP.app</p>
<p>Executable=/Applications/Skipper.app/Contents/MacOS/Skipper<br />
Identifier=com.skipper.Skipper<br />
Format=bundle with Mach-O thin (x86_64)<br />
CodeDirectory v=20100 size=239848 flags=0x0(none) hashes=11986+3 location=embedded<br />
Hash type=sha1 size=20<br />
CDHash=98839e7aa72de4105ac5ad8a2612682ba3bca53f<br />
Signature size=4237<br />
Authority=Developer ID Application: Inventic s.r.o. (6BYV46LH6T)<br />
Authority=Developer ID Certification Authority<br />
Authority=Apple Root CA<br />
Signed Time=03 Feb 2015 17:38:21<br />
Info.plist entries=10<br />
TeamIdentifier=not set<br />
Sealed Resources version=1 rules=4 files=44<br />
Internal requirements count=1 size=300<br />

As it's seems from the verification output, application is correctly signed but OSX doesn't accept it. Another way how to verify application sign status is via **spctl **command:

spctl --assess --type execute --verbose Skipper.app/</p>
<p>Skipper.app/: rejected<br />
source=obsolete resource envelope<br />

We have some error at least. Now it's necessary to find out what is wrong. We can try one more test:

codesign -v Skipper.app/<br />
Skipper.app/: resource envelope is obsolete (version 1 signature)<br />

where we dest little bit more details. All these errors we get only on 10.10 mac, not on 10.9 or older.

After another investigation I found following article. The most important part is:

"Important: For your apps to run on updated versions of OSX they must be signed on OS X version 10.9 or later and thus have a version 2 signature."

Another post about this topic is in felix-schwarz.org blog.

So ,it's bad. We need to update our build machine to 10.9 or at least create new "sign machine" and make sure that everything will work as expected.

Additional links

05 Feb 2015

Posted by: ludek.vodicka

Programming Mac OS #developer #mac #sign

Qt Creator debugger doesn't work after last MacOS 10.9.4 update

Problem is caused by  lldbbridge.py file, where it's necessary to update few lines. After that, debugger will work like charm.

24 Sep 2014

Posted by: ludek.vodicka

Qt Mac OS #Qt #MacOs #debugger #freeze #hangup

Qt5 application hangs-up when QNetworkAccessManager and QEventLoop is used on Mac OS

To be more specific, problem occurs only in very specific circumstances. It's in situation, when application is compiled as console-app and it's compiled on Mac OS X version older than 10.9:

CONFIG -= gui<br />
CONFIG -= console<br />

and when you're using QEventLoop::exec in mode processing all events except user events (QEventLoop::ExcludeUserInputEvents):

</p>
<p>//it's only demonstration, not full code...<br />
QNetworkAccessManager manager; ...<br />
QNetworkRequest request; ...<br />
QNetworkReply *reply = manager-&gt;post(request,arData);<br />
...</p>
<p>eventLoop.exec(QEventLoop::ExcludeUserInputEvents);<br />

In this situation, application hangs-up. When the application is compiled with GUI mode or when application is compiled on Linux/Windows (no matter if gui or console), everything works find. To fix this problem, it's necessary to implement hack similar to this (simplified version):

   bool bAllowUserInputEvents = false;</p>
<p>#if defined(PLATFORM_MACOS) &amp;&amp; defined(AX_APP_CONSOLE)<br />
   bAllowUserInputEvents = true;<br />
#endif</p>
<p>  if ( bAllowUserInputEvents == false )<br />
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);<br />
  else<br />
    eventLoop.exec(QEventLoop::AllEvents);<br />

17 Sep 2014

Tips for versioning systems (Git, svn, mercurial,...)

Get packed archive of changed files from git directory (more info)

zip changes.zip $(git diff --name-only)<br />

Packed last changes of git:

 git archive -o qt-changes.zip head $(git diff --name-only)<br />

How to upgrade svn to 1.7 on Ubuntu 10.4

Here is nice step-by-step manual.

09 Aug 2014

How to change plist value on MacOS 10.9+

When .plist file is manually updated on MacOS 10.9+, changes are not directly applied to plist cache. This means that  these changes aren't visible to executed application (even if you run it after plist change).

It's necessary to tell plist change to reload this settings. There are two ways how to do it. First one is simpler but doesn't work if you completely remove .plist file:

defaults read ~/Library/Preferences/com.xxx.xxx.xxx<br />

Second method is much more efficient, but requires to completely kill plist cache. This cache is immediately executed again and during this launch all plist files are scanned and loaded again:

kill cfprefsd<br />
03 Mar 2014

Posted by: ludek.vodicka

Mac OS #MacOs #plist #cache

Qt app crash on mac when executed with parameters

Our reporting tool occasional crashed on MacOs when was executed with several command line params. Command looked like this:

/app-path/OrmDesigner2 -crash-report -dump-directory /var/folders/4z/k1r35jnn4v77mzl7hzf8wvvw0000gn/T/OrmDesigner2/CrashReports<br />

When inspecting exception report, we found following stack trace:

Thread 0 Crashed:  Dispatch queue: com.apple.main-thread<br />
0   QtCore                         0x0000000100d671da QString::fromLocal8Bit(char const*, int) + 42<br />
1   QtCore                         0x0000000100e72dac QCoreApplication::arguments() + 124<br />
2   QtGui                          0x00000001000de8ef -[QCocoaApplicationDelegate application:openFiles:] + 223<br />
3   com.apple.AppKit               0x00007fff805f3b52 -[NSApplication(NSAppleEventHandling) _handleAEOpenDocumentsForURLs:] + 505<br />
4   com.apple.AppKit               0x00007fff804c0065 -[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] + 217<br />
5   com.apple.Foundation           0x00007fff800f90d6 -[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] + 360<br />
6   com.apple.Foundation           0x00007fff800f8f06 _NSAppleEventManagerGenericHandler + 114<br />
7   com.apple.AE                   0x00007fff82b1c32b aeDispatchAppleEvent(AEDesc const*, AEDesc*, unsigned int, unsigned char*) + 162<br />
8   com.apple.AE                   0x00007fff82b1c224 dispatchEventAndSendReply(AEDesc const*, AEDesc*) + 32<br />
9   com.apple.AE                   0x00007fff82b1c12b aeProcessAppleEvent + 210<br />
10  com.apple.HIToolbox            0x00007fff875ed619 AEProcessAppleEvent + 48<br />
11  com.apple.AppKit               0x00007fff803c5095 _DPSNextEvent + 1191<br />
12  com.apple.AppKit               0x00007fff803c4801 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 155<br />
13  com.apple.AppKit               0x00007fff8038a68f -[NSApplication run] + 395<br />
14  QtGui                          0x00000001000e7c04 QEventDispatcherMac::processEvents(QFlags) + 1588<br />
15  QtCore                         0x0000000100e70774 QEventLoop::processEvents(QFlags) + 68<br />
16  QtCore                         0x0000000100e70a94 QEventLoop::exec(QFlags) + 180<br />
17  QtCore                         0x0000000100e720bc QCoreApplication::exec() + 188<br />
18  com.inventic.ormdesigner       0x0000000100003447 main + 46 (main.cpp:31)<br />
19  com.inventic.ormdesigner       0x00000001000032e0 start + 52<br />

After some google-searching I found out that the problem is in core of our application. When subclassing Qt QApplication, it's necessary to pass argc with reference, not by value. So after adding one little &, everything works like charm!

//construct application object<br />
CApplication(int&amp; argc, char **argv);<br />

External links

01 Mar 2014

Using ssh as proxy/tunnel between Mac OS and Linux

How to connect to remote computer with private key by using ssh:

#register private key<br />
ssh-add ~/dev/Private/ludek_vodicka_dsa.openssh</p>
<p>#connect to computer and forward local port to remote computer and remote port<br />
ssh my-computer.com -p PORT -lUSER -L LOCAL_PORT:REMOTE_COMPUTER:REMOTE_PORT</p>
<p>#connect to computer and create SOCKS proxy on port SOCKS_PORT<br />
ssh my-computer.com -p PORT -lUSER -D SOCKS_PORT<br />

Note:

If your private key was created for Windows, it will probably not work on linux/mac. It's necessary to convert it by using puttygen (on mac or windows). You need to open it by puttygen and choose "Save as openssh" from menu.

Additional resources

07 Feb 2014

Posted by: ludek.vodicka

Linux Mac OS #ssh #tunnel #port-forwarding

Qt on OSX Maverick - Undefined symbols for architecture x86_64

The problem is that starting with OSX 10.9 Apple changed default standard c++ library from libstdc++ to libc++.

Qt binary distribution compile with -stdlib=libstdc++ to be compatible with 10.6, Xcode 5 on 10.9 will select -stdlib=libc++ by default (for OS X 10.7 and better only). So symbol using classes from the standard library (like std::string in this case) will not resolve correctly at link time.

Undefined symbols for architecture x86_64:<br />
&quot;boost::filesystem::path_traits::convert(char const*, char const*, std::basic_string&amp;lt;wchar_t, std::char_traits&amp;lt;wchar_t&amp;gt;, std::allocator&amp;lt;wchar_t&amp;gt; &amp;gt;&amp;amp;, std::codecvt&amp;lt;wchar_t, char, __mbstate_t&amp;gt; const&amp;amp;)&quot;, referenced from:<br />
boost::filesystem::path::wstring(std::codecvt&amp;lt;wchar_t, char, __mbstate_t&amp;gt; const&amp;amp;) const in filePath.o<br />
boost::filesystem::path::wstring(std::codecvt&amp;lt;wchar_t, char, __mbstate_t&amp;gt; const&amp;amp;) const in fileEnumerator.o<br />
boost::filesystem::path::wstring(std::codecvt&amp;lt;wchar_t, char, __mbstate_t&amp;gt; const&amp;amp;) const in directoryHelper.test.o<br />

So it's necessary to compile all libraries with one type of libstdc++ (or libc++). Because I need to keep 10.6 compatibility, it's necessary to compile boost and other libraries with libstdc++ dependency.

To check which library is used, use otool tool:

otool -L library.dylib<br />

As result you will get something like this (check /libc++1.dylib):

otool -L boost/lib/libboost_filesystem.dylib<br />
boost/lib/libboost_filesystem.dylib:<br />
	boost/lib/libboost_filesystem.dylib (compatibility version 0.0.0, current version 0.0.0)<br />
	boost/lib/libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)<br />
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)<br />
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)<br />

How to fix it for boost

it's necessary to recompile boost (and don't forget to remove ./bin.v2 directory) with these params:

  ./b2 cxxflags=&quot;-stdlib=libstdc++&quot; linkflags=&quot;-stdlib=libstdc++&quot; ...<br />

and run otool again:

boost/lib/libboost_filesystem.dylib:<br />
	boost/lib/libboost_filesystem.dylib (compatibility version 0.0.0, current version 0.0.0)<br />
	boost/lib/libboost_system.dylib (compatibility version 0.0.0, current version 0.0.0)<br />
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 60.0.0)<br />
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)<br />

How to fix it for CMake libraries

In case you're using library which is built by CMake system, you  need to add following flag:

cmake -DCMAKE_CXX_FLAGS=&quot;-stdlib=libstdc++&quot;<br />

How to fix other libraries

For any other library it's necessary to pass libstdc++ flag in any available way, for example modify makefile and add :

CXXFLAGS = -stdlib=libstdc++

Second way how to fix it, compile app using latest compiler

Another way is to update mkspecs to compile for latest MacOS version, after that, compiler will be the same like compiler used on all other libraries. To do that, it's necessary to update file:

/usr/local/Qt-5.3.1/mkspecs/macx-clang/qmake.conf

and change following line:

QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6

to latest 10.9 version:

QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.9

More info about this process check here:

http://stackoverflow.com/questions/20342896/solved-qt5-1-qt5-2-mac-os-10-9-mavericks-xcode-5-0-2-undefined-symbols

And that's all

Hope this post saves you a lot of time I have to spent by searching these answers ;-)

External links:

05 Jan 2014

Posted by: ludek.vodicka

Programming Mac OS #Qt #mac #libstdc++ #maverick #clang

Useful Mac OS tools for developer

System Tools

**External articles:**

Programming

  • SmartSVN (free for personal use,  $69/license) - svn gui tool
  • SmartGit/Hg  (free) - git / hg gui tool

File Manager

04 Jan 2014

Posted by: ludek.vodicka

Mac OS #osx #mac #tools

Customize OSX terminal prompt

How to customize default terminal prompt which looks like this?

ComputerName Directory UserName$<br />

simply define PS1 variable with required format. To display only full path, use following:

export PS1=&quot;\w $&quot;<br />
  • \d – date
  • \t – time
  • \h – hostname
  • \# – command number
  • \u – username
  • \W – current directory (e.g.: Desktop)
  • \w – current directory path (e.g.: /Users/Admin/Desktop)

External links:

03 Jan 2014

Posted by: ludek.vodicka

Linux Mac OS #Linux #terminal #osx #prompt

Parse HTTP data to more suitable form

18 Nov 2013

Posted by: ludek.vodicka

Linux Windows Mac OS #nginx

nginx and fast-cgi - tips and tricks

How to pass full path to fast-cgi app

It's necessary to configure which parameters are passed to fast-cgi application from nginx server. For this purposes serves fastcgi_param keyword. It's a good practice to keeps all fastcgi params together. For this purposes nginx has fastcgi.conf file. This file already contains most of useful fastcgi_param bindings.

fastcgi_param  QUERY_STRING       $query_string;<br />
fastcgi_param  REQUEST_METHOD     $request_method;<br />
fastcgi_param  CONTENT_TYPE       $content_type;<br />
...<br />

To include this file use include statement:

location / {<br />
   include fastcgi_params;<br />
   fastcgi_pass 127.0.0.1:9345;<br />
 }<br />

How to pass custom headers to fast-cgi app

Default configuration pass only default headers to fast-cgi. It's necessary to add few more configurations statements:

fastcgi_pass_request_headers on;<br />

After that headers are passed as HTTP_* parameters:

HTTP_HEADER1=2222<br />

External links

18 Nov 2013

Posted by: ludek.vodicka

Programming Linux Windows Mac OS #nginx

FastCGI c++ library for all platforms (Windows, Mac and Linux)

List of existing libraries

Snippets

Stackoverflow articles

Tutorials

Other links

CGICC - how to update it for VS2010 COMPILATION

  •  **error C2668: 'cgicc::copy_if' : ambiguous call to overloaded function** - add cgicc:: to all cgicc::copy_if instances
  •  **error LNK2019: unresolved external symbol** - add compiled .lib path (...Debug\cgicc.lib) to all dependend projects
17 Nov 2013

Posted by: ludek.vodicka

Programming Linux Windows Mac OS #C++ #fastcgi #nginx

C++ Code coverage tools for Windows and Linux (DRAFT)

Linux

  • CovTool - Free test coverage analyzer for C++
  • ggcov -  GTK+ GUI for exploring test coverage data produced by C and C++ programs compiled with gcc --coverage.
  • lcov - graphical front-end for GCC's coverage testing tool gcov. Creates HTML pages containing the source code annotated with coverage information.
  • Trucov - open source program that works with the GCC compiler to display the control flow of a program and its test coverage information

STEPS:

1) add CXX, CFD + LINKER FLAGS

2) remove OBJS output dir and generate .o .gcov,... to root project directory

3)remove MOC directory output for Qt app

3)run gcov xx.cpp

--- generate html

sudo apt-get install lcov (http://ltp.sourceforge.net/coverage/lcov.php)

lcov --capture --directory ~/dev/Applications/AtomixApp/AtomixApp --output-file coverage.info

How to use articles

How to integrate with jenkins

StackOverflow questions

15 Oct 2013

Posted by: ludek.vodicka

Linux Windows Mac OS #code-coverage

Jenkinks and MacOS application signing

After re-installing our MacOS building machine which we're using for ORM Designer deploy, we started to getting following message:

./OrmDesigner2.app: User interaction is not allowed.<br />

After short searching on the internet I found it's required to click on **"Always Allow"** dialog.... which unfortunately we don't have on the console ;-).

The trick is in the keychain unlock. For this purpose we can use following command:

security unlock-keychain -pPASSWORD ~/Library/Keychains/login.keychain<br />

That's all. After this command I'm able to sign my application from Jenkinks command line again.

External links

23 Sep 2013

SVN repository maintenance

To perform SVN repository maintenance use following commands

svnadmin verify REPO</p>
<p>
14 Jun 2013

Posted by: ludek.vodicka

Programming Linux Windows Mac OS #svn

How to sign your Qt Mac OS X App for Gatekeeper

Starting from Mac os 10.8 apple applications requires certificate. Without that certificate (or without additional system tweaks described here on our product support page: http://support.orm-designer.com/5/macos-mountain-lion-10-8-unidentified-developer ) user will se following message:

&quot;OrmDesigner2&quot; can't be opened because it is from an unidentified developer.<br />

[caption id="" align="aligncenter" width="435"] MacOS unidentified developer in ORM Designer[/caption]

Solution

To solve this error message it's necessary to do following steps:

  1. Register in Apple developer program and pay $99 per year
  2. Download and install developer certificate
  3. Sign whole application
  4. Test it!

1) Register on Developer.apple.com

You need to create registration here: https://developer.apple.com/. It's necessary to fill info about contact person and company. After that, your registration will be reviewed by apple team and if everything will be OK, your registration will be approved.

**2) Use Apple site to generate certificates**

Open https://developer.apple.com/account/overview.action ,choose **Certificates, ** Click Add. Than select certificate parameters suitable for your need. In my case it was **Mac Development** and ** Developer ID.**

Now you need to install this certificate to your developer machine. Simply double-click on certificate and let system to import it. You can check that certificate is imported in **Go->Utilities->Keychain Access->login. **Now search for "Developer ID Application: XXXX"

MacOS certificate

**Note: **In my case when I transfer certificate to several developer machines I need to migrate also other Apple certificates. Without that my certificate wasn't a valid.

**3) Sign your application**

Now you need to sign your application including all plugins and frameworks inside app bundle. **After you sing your app, you can't do any changes in the bundle.** So as first run your deploy as usual and as **last step **do app singing.

For ORM Designer sign script looks like this:

#go to deploy directory<br />
cd $StarkDeploy.directory$/deploy</p>
<p>#sign app<br />
codesign --force --verify --verbose --sign &quot;Developer ID Application: Inventic s.r.o.&quot; ./OrmDesigner2.app</p>
<p>#sign all *.dylib files<br />
find OrmDesigner2.app -name *.dylib | xargs -I $ codesign --force --verify --verbose --sign &quot;Developer ID Application: Inventic s.r.o.&quot; $</p>
<p>#sign all Qt* frameworks<br />
find OrmDesigner2.app -name Qt* -type f | xargs -I $ codesign --force --verify --verbose --sign &quot;Developer ID Application: Inventic s.r.o.&quot; $<br />

4) Test it!

As last step it's necessary to test that sign process was successful. As first you can try following command line to validate  it:

codesign -vvv -d OrmDesigner2.app</p>
<p>#RESULT:<br />
Executable=/OrmDesigner2/DeployFiles/macos64/deploy/OrmDesigner2.app/Contents/MacOS/OrmDesigner2<br />
Identifier=com.orm-designer.OrmDesigner2<br />
Format=bundle with Mach-O thin (x86_64)<br />
CodeDirectory v=20100 size=174478 flags=0x0(none) hashes=8717+3 location=embedded<br />
Hash type=sha1 size=20<br />
CDHash=5a491e16f7dcca15b44af4XXXX1a2d2dcc786518<br />
Signature size=4237<br />
Authority=Developer ID Application: Inventic s.r.o. (6BYV46LH6T)<br />
Authority=Developer ID Certification Authority<br />
Authority=Apple Root CA<br />
Signed Time=6 Jun 2013 23:16:08<br />
Info.plist entries=10<br />
Sealed Resources rules=4 files=27<br />
Internal requirements count=1 size=212<br />

Now when you checked that App is correctly signed, it's time to try it on clean computer where no security policy changes was made. Upload your app and execute it.

If you don't see annoying screen "Can't execute application from unidentified developer", **you win** ;-).

External links

**How to transfer certificate: **

**How to import:**

**Apple links**

07 Jun 2013

Posted by: ludek.vodicka

Qt Mac OS #MacOs #certificate #developer

MacOS problem with Java (No Java runtime present)

No Java runtime present, requesting install.<br />
Unable to locate a Java Runtime to invoke.<br />

Execute following command to fix this problem

sudo /usr/libexec/PlistBuddy -c &quot;Delete :JavaWebComponentVersionMinimum&quot; /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/XProtect.meta.plist<br />

more info

https://discussions.apple.com/thread/4761112?start=0&tstart=0

20 May 2013

Posted by: ludek.vodicka

Uncategorized Mac OS #MacOs #java

MacOS open file hander, app icon and other PLIST features

How to configure PLIST

This is how look ORM Designer plist file to correct setup file handler and application icon:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />
&lt;!DOCTYPE plist SYSTEM &quot;file://localhost/System/Library/DTDs/PropertyList.dtd&quot;&gt;<br />
&lt;plist version=&quot;1.0&quot;&gt;<br />
&lt;dict&gt;<br />
  &lt;key&gt;CFBundleVersion&lt;/key&gt;        &lt;string&gt;1.0&lt;/string&gt;<br />
  &lt;key&gt;CFBundlePackageType&lt;/key&gt;    &lt;string&gt;APPL&lt;/string&gt;<br />
  &lt;key&gt;CFBundleExecutable&lt;/key&gt;     &lt;string&gt;@EXECUTABLE@&lt;/string&gt;<br />
  &lt;key&gt;CFBundleIdentifier&lt;/key&gt;     &lt;string&gt;com.orm-designer.OrmDesigner2&lt;/string&gt;<br />
  &lt;key&gt;CFBundleSignature&lt;/key&gt;      &lt;string&gt;????&lt;/string&gt;<br />
  &lt;key&gt;CFBundleGetInfoString&lt;/key&gt;  &lt;string&gt;ORM Designer2, Copyright 2012 Inventic s.r.o.&lt;/string&gt;<br />
  &lt;key&gt;CFBundleIconFile&lt;/key&gt;       &lt;string&gt;@ICON@&lt;/string&gt;<br />
  &lt;key&gt;NOTE&lt;/key&gt;                   &lt;string&gt;ORM Designer2 by Inventic Corporation&lt;/string&gt;</p>
<p>  &lt;key&gt;CFBundleDocumentTypes&lt;/key&gt;<br />
  &lt;array&gt;<br />
    &lt;dict&gt;<br />
      &lt;key&gt;CFBundleTypeName&lt;/key&gt;         &lt;string&gt;ORM Designer project file&lt;/string&gt;<br />
      &lt;key&gt;CFBundleTypeRole&lt;/key&gt;         &lt;string&gt;Editor&lt;/string&gt;<br />
      &lt;key&gt;CFBundleTypeIconFile&lt;/key&gt;     &lt;string&gt;@ICON@&lt;/string&gt;<br />
      &lt;key&gt;LSHandlerRank&lt;/key&gt;            &lt;string&gt;Owner&lt;/string&gt;<br />
      &lt;key&gt;LSIsAppleDefaultForType&lt;/key&gt;  &lt;true/&gt;</p>
<p>      &lt;key&gt;CFBundleTypeExtensions&lt;/key&gt;<br />
      &lt;array&gt;<br />
        &lt;string&gt;ormdesigner&lt;/string&gt;<br />
        &lt;string&gt;ormdes&lt;/string&gt;<br />
        &lt;string&gt;ormdesigner2&lt;/string&gt;<br />
        &lt;string&gt;ormdes2&lt;/string&gt;<br />
      &lt;/array&gt;<br />
    &lt;/dict&gt;<br />
  &lt;/array&gt;<br />
&lt;/dict&gt;<br />
&lt;/plist&gt;<br />

Qt links:

Apple developer links:

Icon converting online tools

19 Sep 2012

Posted by: ludek.vodicka

Programming Mac OS #deploy #mac os

Qt and Google breakpad Windows/Linux/MacOS

Integration of Google breakpad on any platform is really challenge. I didn't figure out how to do it by using recommended ways. So I did it my way ;-)

Create your own Qt project

As first thing I did when integrating Qt and Breakpad is creation of my own .pri file. I manually add all required files from Breakpad one-by-one, starting with src/platform/exception_handler continuing with all files included in previous ones. The complete .pri file you will find at end of this post.

After that I created simple CCrashHandler (inspired by qt-breakpad project) class which register exception handler. It's necessary to implement this handler for each platform separately because each platform have different parameters in google_breakpad::ExceptionHandler() constructor. CrashHandler source code you can find also at end of this post.

Using Breakpad on Linux:

Article about Linux integration.

Notes Linux

  • GCC 4.6.3
  • Ubuntu 12.04.1 32/64bit

Get and Compile Breakpad

#get breakpad latest version<br />
svn checkout http://google-breakpad.googlecode.com/svn/trunk/ google-breakpad-read-only</p>
<p>#compile all breakpad tools for extracting symbol files<br />
./configure<br />
make<br />
sudo make install</p>
<p>#when compilation is ready, you should have installed file dump_syms from original directory /src/tools/linux/dump_syms in your /usr/bin<br />
dump_syms<br />

Generate symbol file and test debug info

Now how to generate and use symbol file:

#generate .sym file<br />
dump_syms ./Application &gt; Application.sym</p>
<p>#store sym file in the correct location<br />
#this step is necessary. Without that minidump_stackwalk tool doesn't work</p>
<p>head -n1 Application.sym<br />
#Result: MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 Application</p>
<p>mkdir -p ./symbols/Application/6EDC6ACDB282125843FD59DA9C81BD830<br />
mv Application.sym ./symbols/Application/6EDC6ACDB282125843FD59DA9C81BD830</p>
<p>#show stack with using minidump_stackwalk tool<br />
minidump_stackwalk ./crash.dmp ./symbols<br />

Result of minidump_stackwalk tool can look like this:

Use additional tools

There is script written by Mozzila corp which simplifies extracting and storing .sym file:
http://mxr.mozilla.org/mozilla-central/source/toolkit/crashreporter/tools/symbolstore.py?raw=1

Now with this script, you can do only one step instead of all described above.

python /path/to/script/symbolstore.py /usr/local/bin/dump_syms ./symbol-storage ./Application<br />

This command correctly creates folder Application/uuid in path symbol-storage and copy generated .sym file inside.

Using Breakpad on MacOS:

To integrate Breakpad and Qt on MacOS I used the same article as for Linux because I'm using gcc and linux-like development toolchain. For native XCode integration you have to probably use this article.

Notes MacOS

  • GCC 4.6.3
  • Qt creator toolchain
  • Mac OS 10.7.3 64bit
  • Don't using any of XCode tool chaing

Do almost all steps like on Linux integration. There is one exception, because you can't compile Breakpad tools using linux-like configure&make. You have to build these tools with XCode.

Compile google_breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj with XCode

Before I managed to successfully compile dump_syms in XCode, I have to update Architectures Debug/Release to 64-bit Intel and BaseSDK to "Latest Mac OS X". I also fix all issues displayed in the left part of XCode window.

Next step is change compilation type from Debug to Release. After a short searching I found a way in "Schema->Edit schema->Build configuration".

To be honest, I was not sure what I did, but it worked ;-). Maybe there is some easier way how to compile dump_syms in xcode, but I don't know how. This was my first contact with XCode ;-).

The application is compiled to path "/Users/User/Library/Developer/Xcode/DerivedData/dump_syms-bjvr/Build/Products/Release/dump_syms". Now copy dump_syms to safe location from where you will use it.

The rest steps are same like in the Linux.

Using Breakpad on Windows

Notes Windows

Article about Windows integration.

  • Compile with Visual Studio 2010
  • Post-mortem debugging is done also via VS2010
  • Google breakpad under windows generates common .dmp files which can by simply load directly to VS

Generate symbol files and test debug info

You have to choices for Windows. First option is use standard .PDB and .DMP files mechanism in VS. Second is use the same way how you can did it for Linux and Mac.

**First way**: Let compiler generate .PDB file. Store this files and use them later in VS together with your crash dump.

**Second way**: Use dump_sys.exe. This file is located in the google breakpad directory tree: google-breakpad\src\tools\windows\binaries\dump_syms.exe .

dump_syms.exe AtomixDevelopment.exe &gt;AtomixDevelopment.sym<br />

And also like under Linux, you can use Python script symbolstore.py to extract symbols to correct directory:

python.exe symbolstore.py binaries\dump_syms.exe .\Symbols AtomixDevelopment.exe<br />

Minidump stackwalk for windows:
http://code.google.com/p/pcxfirefox/source/browse/trunk/betterpgo/talos/talos/breakpad/win32/minidump_stackwalk.exe?r=19

The best thing at end

The most amazing thing I found about dump_syms is their platform independence. If you correctly extract symbol file on each platform and store it in one location, you can analyze any crashdump on one location. No matter what is source platform, you will analyze .dmp file by using **minidump_stackwalk ./crash.dmp ./symbols**.

How to include CrashHandler directly to your project

This is what I get when I follow all includes from **.h** and **.cpp** files starting with exception_handler.h for all platforms. With small modification you can include it to your project and your application will be fully breakpad-able ;-).

# ---------- HEADER -----------------------------------------------------------<br />
OTHERS   += $$PWD/axCrashHandler.pri<br />
HEADERS += $$PWD/CrashHandler.h<br />
SOURCES += $$PWD/CrashHandler.cpp</p>
<p>BREAKPAD_PATH=$$EXTERNAL_LIBRARIES_PATH/breakpad-qt<br />
INCLUDEPATH += $$BREAKPAD_PATH/src</p>
<p>OSMAC {<br />
  HEADERS += $$BREAKPAD_PATH/src/client/mac/handler/exception_handler.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/mac/crash_generation/crash_generation_client.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/mac/crash_generation/crash_generation_server.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/mac/crash_generation/client_info.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/mac/handler/minidump_generator.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/mac/handler/dynamic_images.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/mac/handler/breakpad_nlist_64.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/mac/handler/mach_vm_compat.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/minidump_file_writer.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/minidump_file_writer-inl.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/mac/macho_utilities.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/mac/byteswap.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/mac/MachIPC.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/mac/scoped_task_suspend-inl.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/mac/file_id.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/mac/macho_id.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/mac/macho_walker.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/mac/macho_utilities.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/mac/bootstrap_compat.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/mac/string_utilities.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/linux/linux_libc_support.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/string_conversion.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/md5.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/memory.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/using_std_string.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/convert_UTF.h<br />
  HEADERS += $$BREAKPAD_PATH/src/processor/scoped_ptr.h<br />
  HEADERS += $$BREAKPAD_PATH/src/google_breakpad/common/minidump_exception_mac.h<br />
  HEADERS += $$BREAKPAD_PATH/src/google_breakpad/common/breakpad_types.h<br />
  HEADERS += $$BREAKPAD_PATH/src/google_breakpad/common/minidump_format.h<br />
  HEADERS += $$BREAKPAD_PATH/src/google_breakpad/common/minidump_size.h<br />
  HEADERS += $$BREAKPAD_PATH/src/third_party/lss/linux_syscall_support.h</p>
<p>  SOURCES += $$BREAKPAD_PATH/src/client/mac/handler/exception_handler.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/mac/crash_generation/crash_generation_client.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/mac/crash_generation/crash_generation_server.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/mac/handler/minidump_generator.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/mac/handler/dynamic_images.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/mac/handler/breakpad_nlist_64.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/minidump_file_writer.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/mac/macho_id.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/mac/macho_walker.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/mac/macho_utilities.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/mac/string_utilities.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/mac/file_id.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/mac/MachIPC.mm<br />
  SOURCES += $$BREAKPAD_PATH/src/common/mac/bootstrap_compat.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/md5.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/string_conversion.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/linux/linux_libc_support.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/convert_UTF.c<br />
  LIBS += /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation<br />
  LIBS += /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices<br />
  #breakpad app need debug info inside binaries<br />
  QMAKE_CXXFLAGS+=-g<br />
}</p>
<p>OSLIN {<br />
  HEADERS += $$BREAKPAD_PATH/src/client/linux/handler/exception_handler.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/linux/crash_generation/crash_generation_client.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/linux/handler/minidump_descriptor.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/linux/minidump_writer/minidump_writer.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/linux/minidump_writer/line_reader.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/linux/minidump_writer/linux_dumper.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/linux/minidump_writer/linux_ptrace_dumper.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/linux/minidump_writer/directory_reader.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/linux/log/log.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/minidump_file_writer-inl.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/minidump_file_writer.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/linux/linux_libc_support.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/linux/eintr_wrapper.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/linux/ignore_ret.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/linux/file_id.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/linux/memory_mapped_file.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/linux/safe_readlink.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/linux/guid_creator.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/linux/elfutils.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/linux/elfutils-inl.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/using_std_string.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/memory.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/basictypes.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/memory_range.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/string_conversion.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/convert_UTF.h<br />
  HEADERS += $$BREAKPAD_PATH/src/google_breakpad/common/minidump_format.h<br />
  HEADERS += $$BREAKPAD_PATH/src/google_breakpad/common/minidump_size.h<br />
  HEADERS += $$BREAKPAD_PATH/src/google_breakpad/common/breakpad_types.h<br />
  HEADERS += $$BREAKPAD_PATH/src/processor/scoped_ptr.h<br />
  HEADERS += $$BREAKPAD_PATH/src/third_party/lss/linux_syscall_support.h<br />
  SOURCES += $$BREAKPAD_PATH/src/client/linux/crash_generation/crash_generation_client.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/linux/handler/exception_handler.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/linux/handler/minidump_descriptor.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/linux/minidump_writer/minidump_writer.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/linux/minidump_writer/linux_dumper.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/linux/minidump_writer/linux_ptrace_dumper.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/linux/log/log.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/minidump_file_writer.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/linux/linux_libc_support.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/linux/file_id.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/linux/memory_mapped_file.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/linux/safe_readlink.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/linux/guid_creator.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/linux/elfutils.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/string_conversion.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/convert_UTF.c<br />
  #breakpad app need debug info inside binaries<br />
  QMAKE_CXXFLAGS+=-g<br />
}</p>
<p>OSWIN {<br />
  BREAKPAD_PATH=q:/Applications/breakpad-qt/third-party/latest-breakpad<br />
  INCLUDEPATH += $$BREAKPAD_PATH/src<br />
  HEADERS += $$BREAKPAD_PATH/src/common/windows/string_utils-inl.h<br />
  HEADERS += $$BREAKPAD_PATH/src/common/windows/guid_string.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/windows/handler/exception_handler.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/windows/common/ipc_protocol.h<br />
  HEADERS += $$BREAKPAD_PATH/src/google_breakpad/common/minidump_format.h<br />
  HEADERS += $$BREAKPAD_PATH/src/google_breakpad/common/breakpad_types.h<br />
  HEADERS += $$BREAKPAD_PATH/src/client/windows/crash_generation/crash_generation_client.h<br />
  HEADERS += $$BREAKPAD_PATH/src/processor/scoped_ptr.h </p>
<p>  SOURCES += $$BREAKPAD_PATH/src/client/windows/handler/exception_handler.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/windows/string_utils.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/common/windows/guid_string.cc<br />
  SOURCES += $$BREAKPAD_PATH/src/client/windows/crash_generation/crash_generation_client.cc<br />
}<br />

And this is the minimal implementation of your new CrashHandler. My ownd crash handler is much more sophisticate to perform reporting, sending crash dump etc. But for purposes of this article this is what you need (And also I don't want to share my whole know-how here ;-)))

CrashHandler.h

#pragma once<br />
#include &lt;QtCore/QString&gt;</p>
<p>namespace Atomix<br />
{<br />
	class CrashHandlerPrivate;<br />
	class CrashHandler<br />
	{<br />
	public:<br />
		static CrashHandler* instance();<br />
    void Init(const QString&amp;  reportPath);</p>
<p>		void setReportCrashesToSystem(bool report);<br />
		bool writeMinidump();</p>
<p>	private:<br />
		CrashHandler();<br />
		~CrashHandler();<br />
		Q_DISABLE_COPY(CrashHandler)<br />
		CrashHandlerPrivate* d;<br />
	};<br />
}<br />

CrashHandler.cpp

#include &quot;CrashHandler.h&quot;<br />
#include &lt;QtCore/QDir&gt;<br />
#include &lt;QtCore/QProcess&gt;<br />
#include &lt;QtCore/QCoreApplication&gt;<br />
#include &lt;QString&gt;</p>
<p>#if defined(Q_OS_MAC)<br />
#include &quot;client/mac/handler/exception_handler.h&quot;<br />
#elif defined(Q_OS_LINUX)<br />
#include &quot;client/linux/handler/exception_handler.h&quot;<br />
#elif defined(Q_OS_WIN32)<br />
#include &quot;client/windows/handler/exception_handler.h&quot;<br />
#endif</p>
<p>namespace Atomix<br />
{<br />
	/************************************************************************/<br />
	/* CrashHandlerPrivate                                                  */<br />
	/************************************************************************/<br />
	class CrashHandlerPrivate<br />
	{<br />
	public:<br />
		CrashHandlerPrivate()<br />
		{<br />
			pHandler = NULL;<br />
		}</p>
<p>		~CrashHandlerPrivate()<br />
		{<br />
			delete pHandler;<br />
		}</p>
<p>		void InitCrashHandler(const QString&amp; dumpPath);<br />
		static google_breakpad::ExceptionHandler* pHandler;<br />
		static bool bReportCrashesToSystem;<br />
	};</p>
<p>	google_breakpad::ExceptionHandler* CrashHandlerPrivate::pHandler = NULL;<br />
	bool CrashHandlerPrivate::bReportCrashesToSystem = false;</p>
<p>	/************************************************************************/<br />
	/* DumpCallback                                                         */<br />
	/************************************************************************/<br />
#if defined(Q_OS_WIN32)<br />
	bool DumpCallback(const wchar_t* _dump_dir,const wchar_t* _minidump_id,void* context,EXCEPTION_POINTERS* exinfo,MDRawAssertionInfo* assertion,bool success)<br />
#elif defined(Q_OS_LINUX)<br />
	bool DumpCallback(const google_breakpad::MinidumpDescriptor &amp;md,void *context, bool success)<br />
#elif defined(Q_OS_MAC)<br />
	bool DumpCallback(const char* _dump_dir,const char* _minidump_id,void *context, bool success)<br />
#endif<br />
	{<br />
		Q_UNUSED(context);<br />
#if defined(Q_OS_WIN32)<br />
		Q_UNUSED(_dump_dir);<br />
		Q_UNUSED(_minidump_id);<br />
		Q_UNUSED(assertion);<br />
		Q_UNUSED(exinfo);<br />
#endif<br />
		qDebug(&quot;BreakpadQt crash&quot;);</p>
<p>		/*<br />
		NO STACK USE, NO HEAP USE THERE !!!<br />
		Creating QString's, using qDebug, etc. - everything is crash-unfriendly.<br />
		*/<br />
		return CrashHandlerPrivate::bReportCrashesToSystem ? success : true;<br />
	}</p>
<p>	void CrashHandlerPrivate::InitCrashHandler(const QString&amp; dumpPath)<br />
	{<br />
		if ( pHandler != NULL )<br />
			return;</p>
<p>#if defined(Q_OS_WIN32)<br />
		std::wstring pathAsStr = (const wchar_t*)dumpPath.utf16();<br />
		pHandler = new google_breakpad::ExceptionHandler(<br />
			pathAsStr,<br />
			/*FilterCallback*/ 0,<br />
			DumpCallback,<br />
			/*context*/<br />
			0,<br />
			true<br />
			);<br />
#elif defined(Q_OS_LINUX)<br />
		std::string pathAsStr = dumpPath.toStdString();<br />
		google_breakpad::MinidumpDescriptor md(pathAsStr);<br />
		pHandler = new google_breakpad::ExceptionHandler(<br />
			md,<br />
			/*FilterCallback*/ 0,<br />
			DumpCallback,<br />
			/*context*/ 0,<br />
			true,<br />
			-1<br />
			);<br />
#elif defined(Q_OS_MAC)<br />
		std::string pathAsStr = dumpPath.toStdString();<br />
		pHandler = new google_breakpad::ExceptionHandler(<br />
			pathAsStr,<br />
			/*FilterCallback*/ 0,<br />
			DumpCallback,<br />
			/*context*/<br />
			0,<br />
			true,<br />
			NULL<br />
			);<br />
#endif<br />
	}</p>
<p>	/************************************************************************/<br />
	/* CrashHandler                                                         */<br />
	/************************************************************************/<br />
	CrashHandler* CrashHandler::instance()<br />
	{<br />
		static CrashHandler globalHandler;<br />
		return &amp;globalHandler;<br />
	}</p>
<p>	CrashHandler::CrashHandler()<br />
	{<br />
		d = new CrashHandlerPrivate();<br />
	}</p>
<p>	CrashHandler::~CrashHandler()<br />
	{<br />
		delete d;<br />
	}</p>
<p>	void CrashHandler::setReportCrashesToSystem(bool report)<br />
	{<br />
		d-&gt;bReportCrashesToSystem = report;<br />
	}</p>
<p>	bool CrashHandler::writeMinidump()<br />
	{<br />
		bool res = d-&gt;pHandler-&gt;WriteMinidump();<br />
		if (res) {<br />
			qDebug(&quot;BreakpadQt: writeMinidump() successed.&quot;);<br />
		} else {<br />
			qWarning(&quot;BreakpadQt: writeMinidump() failed.&quot;);<br />
		}<br />
		return res;<br />
	}</p>
<p>	void CrashHandler::Init( const QString&amp; reportPath )<br />
	{<br />
		d-&gt;InitCrashHandler(reportPath);<br />
	}<br />
}<br />

Main.cpp

And here is how to use it:

#include &quot;axCore/axCrashHandler/CrashHandler.h&quot;<br />
#include &lt;QDebug&gt;<br />
#include &lt;QCoreApplication&gt;<br />
#include &lt;iostream&gt;</p>
<p>int buggyFunc()<br />
{<br />
	delete reinterpret_cast&lt;QString*&gt;(0xFEE1DEAD);<br />
	return 0;<br />
}</p>
<p>int main(int argc, char * argv[])<br />
{<br />
	qDebug() &lt;&lt; &quot;App start&quot;;<br />
	QCoreApplication app(argc, argv);</p>
<p>#if defined(Q_OS_WIN32)<br />
	Atomix::CrashHandler::instance()-&gt;Init(&quot;c:\\dump&quot;);<br />
#elif defined(Q_OS_LINUX)<br />
	Atomix::CrashHandler::instance()-&gt;Init(&quot;/Users/dev/dump&quot;);<br />
#elif defined(Q_OS_MAC)<br />
	Atomix::CrashHandler::instance()-&gt;Init(&quot;/Users/User/dump&quot;);<br />
#endif</p>
<p>	qDebug() &lt;&lt; &quot;CrashHandlerSet&quot;;<br />
	buggyFunc();<br />
	return 0;<br />
}<br />

Very slow svn updates from Virtual Machines (VMWare)

I have a lot of virtual machines used for my everyday development. It's very frustrating the SVN update speed if you have several externals in your main SVN source.

Today when I wait for some compilation start searching if there is anything what could improve SVN speed. After searching a lot of articles about faster network, better server hdd,... I found article with mention how SVN client communicate with server (intensively ;-) ). But without any clue how to improve it.

So I start searching how SVN client communiacte from within VMWare machines to server. I noticed that VMWare default network settings is NAT: Used to share the host's IP address:

So I start trying other network methods and this is the result:

When I use "Custom: Specific virtual network" and choose "VMnet0 Bridged", my svn update is about ten times faster than on NAT settings!!. I also tried first option "Bridged:..." but this doesn't work for me.

30 Aug 2012

Posted by: ludek.vodicka

Linux Windows Mac OS #deploy #svn

How to setup MacOS terminal to have color output

Add these lines to your ~/.bash_profile file.

export CLICOLOR=1</p>
<p>#if your're using white background<br />
export LSCOLORS=ExFxCxDxBxegedabagacad</p>
<p>#if your're using black backgroud<br />
#export LSCOLORS=gxBxhxDxfxhxhxhxhxcxcx<br />
30 Aug 2012

Posted by: ludek.vodicka

Mac OS #MacOs #terminal

QWidget: Must construct a QApplication before a QPaintDevice

Today I encounter this error after applying **macdeployqt** to my application. There is a lot of questions about this topic on google but not very answers.

The most important thing is setup following variable.

export DYLD_PRINT_LIBRARIES=1<br />

Using this you will se which libraries are loaded during execution of your application. The interesting thing is, that I see loading a libraries from their original directories instead of Application.app. But when I temporary moved these libraries from their location, libraries begin to load from then bundle location.

The reason for my "QWidget: Must construct a QApplication before a QPaintDevice" was executing an older version of QTitanRibbon from shared libraries path instead of the newest one compiled directly to /usr/lib.
The second reason for this issue was caused by another path in "export DYLD_LIBRARY_PATH". It seems that application search for libraries first in DYLD_LIBRARY_PATH and after in paths from their inner records.

To turn off this debug output, use:

unset DYLD_PRINT_LIBRARIES<br />

29 Aug 2012

Posted by: ludek.vodicka

Programming Qt Mac OS #Qt #MacOs #deploy

Mac OS - How to detect library destination platform

Today I need to check if one of third-party component compile correctly 64-bit library version.

lipo -info /path/to/library<br />
21 Aug 2012

Posted by: ludek.vodicka

Mac OS

Windows, Linux and MacOS 7za equivalent

**Windows:**
http://www.7-zip.org/

**Ubuntu:**

sudo apt-get install p7zip-full<br />

**MacOS:**

sudo port install p7zip<br />

21 Aug 2012

Posted by: ludek.vodicka

Linux Windows Mac OS

How to create nice MacOS DMG installer

In this article I will show how to create DMG installer in reusable way. The most of things and ideas presented here are ideas from several articles mentioned on the end of this article.

1) As first step we need to create our DMG template with link to Applications.
2) Next we have to modify the visual representation of DMG file.
3) Next we store created DMG as template
4) Now mount copied template as directory, fill DMG with real files
5) Detach mounted DMG, pack DMG
6) Distribute app ;-)

More detailed info about all these steps you will find in articles mentioned below. Here is a short script I wrote for three-phase deploying (1) create template, 2) pack template, 3)fill template with real data and compress it)

#! /bin/bash</p>
<p>TEMPLATE_DMG=atomix-development-template.dmg<br />
VOLUME_NAME=&quot;Atomix Development&quot;<br />
APPLICATION_FILE_NAME=&quot;AtomixDevelopment.app&quot;</p>
<p>if [ &quot;$1&quot; = &quot;create-template&quot; ]<br />
then<br />
  echo Create DMG template<br />
  mkdir template<br />
  cd template<br />
  mkdir $APPLICATION_FILE_NAME<br />
  touch $APPLICATION_FILE_NAME/fake<br />
  ln -s /Applications/ Applications<br />
  cd ..<br />
  rm $TEMPLATE_DMG<br />
  rm $TEMPLATE_DMG.bz2<br />
  hdiutil create -fs HFSX -layout SPUD -size 100m &quot;$TEMPLATE_DMG&quot; -srcfolder template -format UDRW -volname &quot;$VOLUME_NAME&quot; -quiet<br />
  rm -rf template<br />
elif [ &quot;$1&quot; = &quot;zip-template&quot; ]<br />
then<br />
  echo Zipping DMG template<br />
  bzip2 &quot;$TEMPLATE_DMG&quot;<br />
elif [ &quot;$1&quot; = &quot;create-dmg&quot; ]<br />
then<br />
  echo Creating DMG file from template and data</p>
<p>  #unzip template<br />
  rm $TEMPLATE_DMG<br />
  bunzip2 -k $TEMPLATE_DMG.bz2</p>
<p>  #create pack path and attach DMG<br />
  PACK_PATH=`pwd`/dmg-pack<br />
  mkdir $PACK_PATH<br />
  hdiutil attach &quot;$TEMPLATE_DMG&quot; -noautoopen -quiet -mountpoint &quot;$PACK_PATH&quot;</p>
<p>  #copy new content to DMG<br />
  cp -r &quot;$2&quot; &quot;$PACK_PATH&quot;<br />
  rm $PACK_PATH/$APPLICATION_FILE_NAME/fake</p>
<p>  #detach DMG, remove mount path<br />
  hdiutil detach &quot;$PACK_PATH&quot; -force -quiet<br />
  rm -rf $PACK_PATH</p>
<p>  #compress DMG<br />
  hdiutil convert -format UDZO -o tmp-packer-output.dmg &quot;$TEMPLATE_DMG&quot; -imagekey zlib-level=9<br />
  rm ./$TEMPLATE_DMG<br />
  mv ./tmp-packer-output.dmg $TEMPLATE_DMG</p>
<p>  #rm $TEMPLATE_DMG<br />
else<br />
  echo Missing parameter<br />
  echo &quot;create-dmg [create|zip-template|create-dmg Path/Application.app]&quot;<br />
fi<br />

So, it looks like that DMG file for ORM Designer2 is ready ;-)

Another tools to create DMG package

External links

http://codevarium.gameka.com.br/how-to-create-your-own-beautiful-dmg-files/
http://el-tramo.be/guides/fancy-dmg/
http://stackoverflow.com/questions/96882/how-do-i-create-a-nice-looking-dmg-for-mac-os-x-using-command-line-tools
http://stackoverflow.com/questions/8680132/creating-nice-dmg-installer-for-mac-os-x
http://stackoverflow.com/questions/2104364/how-to-install-a-qt-application-on-a-customers-system

16 Aug 2012

Posted by: ludek.vodicka

Qt Mac OS #MacOs #deploy

How to deploy Qt application on MacOS - part II

In first part of this article I introduced a manual way how to deploy MacOS application. Because doing all these stuff manually was a lot of hand work, Qt introduced small tool called **macdeployqt**.

This utility looks very good, but also have some drawbacks. As first I will show you how utility works:

macdeployqt Application.app<br />

That's all ;-). This command should do all the hard work for you. But in some cases it didn't.

ERROR: no file at &quot;/usr/lib/libboost_iostreams.dylib&quot;<br />
ERROR: no file at &quot;/usr/lib/libboost_filesystem.dylib&quot;<br />
ERROR: no file at &quot;/usr/lib/libboost_system.dylib&quot;<br />
ERROR: no file at &quot;/usr/lib/libboost_thread.dylib&quot;<br />
ERROR: no file at &quot;/usr/lib/libboost_date_time.dylib&quot;<br />
ERROR: no file at &quot;/usr/lib/libboost_regex.dylib&quot;<br />
ERROR: no file at &quot;/usr/lib/libboost_chrono.dylib&quot;<br />
ERROR: no file at &quot;/usr/lib/libyaml-cpp.0.2.dylib&quot;<br />

The problem is that libraries mentioned in the previous list doesn't has included absolute path. If you inspecit this library, you will se this:

otool -L libboost_regex.dylib<br />
libboost_regex.dylib:<br />
	libboost_regex.dylib (compatibility version 0.0.0, current version 0.0.0)<br />
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0)<br />
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)<br />

And this is the problem. Inner path in library is only filename without full path, so when we link library with our executable, our executable also has only relative path. And when macdeployqt try to find this library, automatically try to search in /usr/lib.

One possible solution is copy libraries to /usr/lib. Second solution is update paths in libraries to absolute paths. The third way is fix library linker to include full paths in libraries.

I found out that the simplies way how to fix it is call install_name_tool after library compilation and fix the path (don't forget to update library paths inside other library paths!)

  install_name_tool -id &quot;$SHL_PATH/boost/lib/libboost_chrono.dylib&quot; $SHL_PATH/boost/lib/libboost_chrono.dylib<br />
  install_name_tool -id &quot;$SHL_PATH/boost/lib/libboost_date_time.dylib&quot; $SHL_PATH/boost/lib/libboost_date_time.dylib<br />
  ...<br />
  install_name_tool -change &quot;libboost_system.dylib&quot; &quot;$SHL_PATH/boost/lib/libboost_system.dylib&quot; $SHL_PATH/boost/lib/libboost_chrono.dylib<br />
  install_name_tool -change &quot;libboost_system.dylib&quot; &quot;$SHL_PATH/boost/lib/libboost_system.dylib&quot; $SHL_PATH/boost/lib/libboost_filesystem.dylib<br />

So, now when we have updated all libraries, we can try to create application bundle again

macdeployqt AtomixDevelopment.app/<br />

And if we did everything correctly, now we should have a working app ;-).

Troubleshooting

In some cases you can get error "Permission defined", "Bad file descriptor" or other similar errors when using macdeployqt.

ERROR: &quot;install_name_tool: can't open input file: OrmDesigner2.app/Contents/Frameworks//libssl.1.0.0.dylib for writing (Permission denied)<br />
install_name_tool: can't lseek to offset: 0 in file: OrmDesigner2.app/Contents/Frameworks//libssl.1.0.0.dylib for writing (Bad file descriptor)<br />
install_name_tool: can't write new headers in file: OrmDesigner2.app/Contents/Frameworks//libssl.1.0.0.dylib (Bad file descriptor)<br />
install_name_tool: can't close written on input file: OrmDesigner2.app/Contents/Frameworks//libssl.1.0.0.dylib (Bad file descriptor)<br />

The reason is insufficient permissions for modifying copied libraries. Simple execute

sudo macdeployqt<br />

and everything should work ok. Another workaround for this issue is using newer version of Qt. I figured out that on MacOS I wrongly use Qt 4.7.4. When I correct this to version Qt 4.8.2 this issue was solved.

DMG file

If you want to create simply DMG file, simply call macdeployqt with param --dmg. But this dmg doesn't look so good:

This will need more investigation how to make DMG files nicer ;-).

Notes

  • Everytime you run macdeployqt run it on clean folder. The best way is to call rm -rf Application, compile app and than run macdeployqt

Notes to bug in macdeployqt

The problem is caused by invalid permissions. Copied libraries have the same permissions like in the source location. There are three different solutions:

  1. Use sudo and execute macdeployqt with root permissions
  2. Update external libraries permissions to rw, so also copies will have a correct permissions
  3. Update macdeployqt script. In file shared.cpp on line 91 is method copyFilePrintStatus. Here is a necessary to update copied files permissions to correct rw

In my case the problem was in file liblzma.5.dylib

Frameworks/liblzma.5.dylib is not writable (Permission denied)<br />

Orinal library is located in path:

/usr/local/Cellar/xz/5.0.4/lib<br />
16 Aug 2012

Posted by: ludek.vodicka

Qt Mac OS #Qt #MacOs #deploy

How to hack HOME and END keys on MacOS to behave like on Windows

It’s really annoying that HOME and END on MacOS behaves differently than on Windows. If you want to remap all these keys, use tool called KeyRemap4MacBook.

Not working solution ;-)

Here is simply way how to change it (copied from evansweb):

I have found a way to “fix” this problem by editing the default keybindings file,~/Library/KeyBindings/DefaultKeyBinding.dict. Create the directory and / or the file if they’re not already there, and make it look like this:

{
        /* Remap Home / End to be correct :-) */
        "\UF729"  = "moveToBeginningOfLine:";                   /* Home         */
        "\UF72B"  = "moveToEndOfLine:";                         /* End          */
        "$\UF729" = "moveToBeginningOfLineAndModifySelection:"; /* Shift + Home */
        "$\UF72B" = "moveToEndOfLineAndModifySelection:";       /* Shift + End  */
}

External source:
http://lifehacker.com/225873/mac-switchers-tip--remap-the-home-and-end-keys
http://evansweb.info/2005/03/24/mac-os-x-and-home-end-keys
http://soodev.wordpress.com/2011/07/04/mac-os-x-remapping-home-and-end-keys/

16 Aug 2012

Posted by: ludek.vodicka

Mac OS

How to deploy Qt application on MacOS - part I

As I wrote yesterday, I found the way how to proceed deployment on the Linux system. Today I have to manage it the same on the MacOS systems.

Note: the simplest way is introduced in the second part of this article.

The first usefull command for tracking dependencies between your application and other shared libraries is otool:

#path to executable, not .App directory!<br />
otool -L Application.app/Contents/MacOS/AppExecutable<br />

Now we can see paths to our libraries. The bad news is that MacOS doesn't have any -RPATH and $ORIGIN. The good news is utility install_name_tool and variable @executable_path which works similar like $ORIGIN.
Note: For newer versions of MacOS there are more variables like @executable_path. On version 10.4 was introduced @loader_path and on version 10.5 apple introduce @rpath variable.

The step-by-step solution

As first step it's necessary to upload all dependent libraries directly to the Application.app/Contents/MacOS/. For list all required files use otool:

cd Application.app/Contents/MacOS<br />
otool -L AppExecutable<br />

When we have copied all libraries, we need to change paths **for** and **in** all libraries.

Here is example how to set libxml2 library. As first step we will check how is library referred.

$user otool -L AtomixDevelopment</p>
<p>AtomixDevelopment:<br />
	libboost_iostreams.dylib (compatibility version 0.0.0, current version 0.0.0)<br />
	libboost_filesystem.dylib (compatibility version 0.0.0, current version 0.0.0)<br />
	/Users/User/dev/SharedLibraries/libxml/lib/libxml2.2.dylib (compatibility version 10.0.0, current version 10.8.0)<br />
	/Users/User/dev/SharedLibraries/libxslt/lib/libxslt.1.dylib (compatibility version 3.0.0, current version 3.26.0)<br />
	/Users/User/dev/SharedLibraries/libxslt/lib/libexslt.0.dylib (compatibility version 9.0.0, current version 9.15.0)<br />

And Library:

User$ otool -L libxml2.2.dylib<br />
libxml2.2.dylib:<br />
	/Users/User/dev/SharedLibraries/libxml/lib/libxml2.2.dylib (compatibility version 10.0.0, current version 10.8.0)<br />
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)<br />
	/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5)<br />
	/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)<br />

When we checked libxml2.2.dylib library with otool, we can see that library has hardocoded our development path. This isn't good ;-). So we now change this value to path relative to the executable and again verify this inner path.

install_name_tool -id &quot;@loader_path/libxml2.2.dylib&quot; libxml2.2.dylib<br />
otool -L libxml2.2.dylib<br />
libxml2.2.dylib:<br />
	@loader_path/libxml2.2.dylib (compatibility version 10.0.0, current version 10.8.0)<br />
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)<br />
	/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5)<br />
	/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)<br />

As you can see, now is path (first line) set up to reffer @loader_path/libxml2.2.dylib. It's correct now. As second step we have to update path in our executable, because also there is path hardcoded to our library repository.

install_name_tool -change &quot;/Users/User/dev/ExternalLibraries/../SharedLibraries/libxml/lib/libxml2.2.dylib&quot; &quot;@loader_path/libxml2.2.dylib&quot; AtomixDevelopment</p>
<p>otool -L AtomixDevelopment<br />
AtomixDevelopment:<br />
	libboost_iostreams.dylib (compatibility version 0.0.0, current version 0.0.0)<br />
	libboost_filesystem.dylib (compatibility version 0.0.0, current version 0.0.0)<br />
	@loader_path/libxml2.2.dylib (compatibility version 10.0.0, current version 10.8.0)<br />
        ...<br />

So, now we have changed also path in our executable. And now we need to do all these steps for all libraries..... ;-).

 

Notes

To follow the MacOS application convention it's better to place libraries to folder Application.app/Contents/Frameworks. Here is a directory schema for Qt example application plugAndPaint.

External links

16 Aug 2012

Posted by: ludek.vodicka

Qt Mac OS #Qt #MacOs #deploy

Strange "no matching function for call to ..." error on MacOS

Error appear when using BOOST::fusion::map<....>

Error message:

In file included from axOrm/ormObject/ormObject.test.cpp:5:<br />
axOrm/ormObject/testObjects/objContactAndAddress.h: In member function 'void Atomix::Orm::Tests::CBaseOrmContact::SetName(XString)':<br />
axOrm/ormObject/testObjects/objContactAndAddress.h:92: error: no matching function for call to 'Atomix::Orm::Tests::CBaseOrmContact::GetPropertyHolder()'<br />

Invalid source code

template &lt;class TNameParam&gt; typename fus::result_of::at_key&lt; TmapAssociations,TNameParam&gt;::type &amp; GetAssociationHolder()<br />
{ return fus::at_key&lt;TNameParam&gt;(m_mapAssociations); }<br />

for fix simply change result_of::at_key to result_of::value_at_key

template &lt;class TNameParam&gt; typename fus::result_of::value_at_key&lt;TmapAssociations,TNameParam&gt;::type &amp; GetAssociationHolder()<br />

After fixing this error, you can achieved problem with const modifier. Correct syntax for const definition is:

template <typename TNameParam> typename fus::result_of::value_at_key<const TmapProperties,TNameParam>::type const & GetPropertyHolder() const
{ return fus::at_key<TNameParam>(m_mapProperties); }

28 Jun 2011

Posted by: ludek.vodicka

Programming Mac OS #MacOs #C++ #g++

MacOS tips

How to mount .dmg file using command line

hdiutil attach ./file.dmg<br />

for detach image use

hdiutil detach /Volumes/SomeVolume<br />

How to execute application in .pkg

open app.pkg<br />

16 Dec 2010

Posted by: ludek.vodicka

Mac OS #MacOs