Results 1 to 14 of 14

Thread: Calling external programs via QProcess on Mac OS

  1. #1
    Join Date
    May 2009
    Location
    Berlin
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Question Calling external programs via QProcess on Mac OS

    I'm quite new to MacOS and I'm trying to build my program on Mac OS for the first time. So far Windows and Linux were my target platforms. Everything works fine and I'm again impressed on the degree of platform independence that Qt offers.

    But there is one problem:

    I have a program (assume it's called foo) that attempts to call external tools (latex, gs) via QProcess. It should be quite straight forward and works fine on Windows and Linux


    Qt Code:
    1. QProcess process;
    2.  
    3. process.start("latex ......");
    4.  
    5. bool success = process.waitForStarted();
    6.  
    7. if(!success)
    8. {
    9. int error = process.error();
    10. qDebug("waitForStarted: error=%d\n", error);
    11. ....
    12. }
    To copy to clipboard, switch view to plain text mode 

    On Mac OS that simply doesn't work when I launched my application (foo) via the bundle file (foo.app). process.start() returns false and the error code is 0. But it works fine when I start foo via the executable that is inside the bundle under foo.app/Contents/MacOS/foo

    I notice that in that case a shell window pops up. Perhaps now it is executed in a different execution environment. Now foo can call all external tools.

    Assuming it is perhaps the PATH variable from the environment, I tried to add the required path entries to the process environment with

    Qt Code:
    1. QProcessEnvironment sysenv = QProcessEnvironment::systemEnvironment();
    2. QString path = sysenv.value("PATH");
    3. if(path != "")
    4. path += ":";
    5. path += "/usr/texbin:/usr/local/bin";
    6.  
    7. sysenv.remove("PATH");
    8. sysenv.insert("PATH", path);
    9.  
    10. process.setProcessEnvironment(sysenv);
    To copy to clipboard, switch view to plain text mode 

    It still doesn't work. Even if it would, I would prefer not messing around with PATH values. How can I get the same execution execution environment as in the shell? Do I have to wrap my call inside a script and execute that via "sh"?

    Why is a program started in a different context depending on whether the bundle or the exe from within the bundle is run?

    Google didn't really help on that.
    Last edited by berliner; 14th February 2011 at 21:54.

  2. #2
    Join Date
    Aug 2011
    Posts
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Calling external programs via QProcess on Mac OS

    Hi,

    I'm having exactly the same issue, did you manage to figure out?

    Thanks

  3. #3
    Join Date
    Jul 2011
    Posts
    42
    Thanks
    4
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Calling external programs via QProcess on Mac OS

    Well i had a similar problem in Mac. There's a really weird thing regarding enviroments on Mac. Running from Finder is totally diferent than running from console, and so is the excecution of the Apps and the actual exceutable inside MacOS.

    The only way to make it work by launching from the .app is to set the paths of the external tools properly. We did a AppleScript that sets all the enviromental variables that we needed, and then calls the exceutable on Contents/MacOs/xxx to run on the background.
    Thats really a windows approach adapted to Mac's architecture, as far as i know, mac handles all those things with the plist.info and files like those, inside that Contents/ structure.

    Here's the applescript that we made:
    Qt Code:
    1. tell application "Finder" to get folder of (path to me) as Unicode Text
    2. set workingDir to POSIX path of result
    3. do shell script "export PATH=$PATH:" & "workingDir & "/bin/; export DYLD=LIBRARY_PATH=& workingDir & "/bin/; cd " & workingDir & "/bin/MyProgram.app/Contents/MacOS/; ./MyProgram &"
    To copy to clipboard, switch view to plain text mode 

    1st line --> this finds the absolute path of where u are clicking on finder
    2nd line --> saves the path to the workingDir variable
    3rd line --> we call a shell script in a huge command (because if u do it in separate ways, it looses the previous), and we add the paths needed for execution, as well a dinamyc libraries, and finally call the executable on the background

    If you dont want to run it from Finder, then u can take a simpler approach and create a simple bash script that adds those paths to the enviroment and then executes the .exe inside MacOS

    Hope this helps.

  4. The following user says thank you to superpacko for this useful post:

    berliner (2nd January 2012)

  5. #4
    Join Date
    May 2009
    Location
    Berlin
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Calling external programs via QProcess on Mac OS

    I'm pulling this up, because I found another possible way of dealing with that problem. That "solution" would use the ability of app bundles to run binaries that exist witih the bundle.

    If my app bundle contains...

    ./Foo.app/Contents/MacOS/foo
    ./Foo.app/Contents/MacOS/bar

    ...then the Foo.app can call the bar executable.

    But I want to execute something outside i.e. ghostscript. So I created a symbolic link:
    ln -s /usr/local/bin/gs ./Foo.app/Contents/MacOS/gs

    Now Foo.app can execute gs without problem. As far as I can rely on /usr/local/bin/ to be the standard location, I can even distribute Foo.app with the symbolic link itside. If not, I would need some kind of installation step that involves creating the symbolic link. The question now is, if that is kind of acceptable as solution?

    (and I still don't understand why Apple decided to implement that annoying limitation)

    The weird thing is that the problem is almost unknown in Google. Seems as if Mac applications never have to call anything outside the bundle, which is kind of unlikely.

  6. #5
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Calling external programs via QProcess on Mac OS

    I use QProcess on the Mac to run ffprobe and ffmpeg successfully. All it took was to ensure that the PATH environmental variable contained the path for ffprobe and ffmpeg. Here's the code I use to prepend the PATH with /opt/local/bin, /usr/local/bin, and $HOME/bin, etc.

    Qt Code:
    1. QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    2. QStringList envlist = env.toStringList();
    3. envlist.replaceInStrings(QRegularExpression("^(?i)PATH=(.*)"), "PATH=/opt/local/bin:/usr/local/bin:$HOME/bin:\\1");
    4. QProcess ffprobe;
    5. ffprobe.setEnvironment(envlist);
    To copy to clipboard, switch view to plain text mode 

    Hope that helps.

    Jeff

  7. #6
    Join Date
    May 2009
    Location
    Berlin
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Calling external programs via QProcess on Mac OS

    Yes, I had that idea. I modify the PATH, I print it to confirm that it really got modifie, but it's still not working.

    process.waitForStarted() just returns false and process.error() reports 0.

    Did your case really work for an application bundle? It works for me too when I directly start the binary that resides inside the bundle. Thene the program seems to get the regular execution environment. But I want to deliver an application bundle, because it makes it easier to include the Qt libraries.

    Meanwhile I created something in between. I used macdeployqt to create the bundle with all dependencies. Then I changed the bundles name and created a symbolic link in the top directory of the bundle that points to the binary under MacOS. The structure is then like this

    /Foo.app/Contents/MacOS/foo
    /Foo.app/foo -> Contents/MacOS/foo

    Now the user can run the program without traversing down the directory structure. But I still don't like it.
    Last edited by berliner; 6th December 2014 at 21:18.

  8. #7
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Calling external programs via QProcess on Mac OS

    Since you ran macdeployqt against your bundle, it should have copied all of the Qt frameworks into your Foo.app/Contents/Frameworks directory. My guess is that the Qt framework libraries are not able to be located when you try to start the process.

    Can you cd to your app bundle as follows and show output from otool?

    Qt Code:
    1. cd /Applications/Foo.app/Contents/MacOS
    2. otool -L foo
    To copy to clipboard, switch view to plain text mode 

    The commands above will show the library dependencies for your foo executable. Additionally, if you'll run the following, it will display the rpath(s) in your executed with the section identified by "LC_RPATH". First command switch was an uppercase "L", the one below is a lowercase "l":

    Qt Code:
    1. otool -l foo
    To copy to clipboard, switch view to plain text mode 

    Thanks,

    Jeff

  9. #8
    Join Date
    May 2009
    Location
    Berlin
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Calling external programs via QProcess on Mac OS

    Thanks for your efforts. Here is the output from otool.

    otool -L

    Qt Code:
    1. @loader_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets (compatibility version 5.3.0, current version 5.3.1)
    2. @loader_path/../Frameworks/QtGui.framework/Versions/5/QtGui (compatibility version 5.3.0, current version 5.3.1)
    3. @loader_path/../Frameworks/QtCore.framework/Versions/5/QtCore (compatibility version 5.3.0, current version 5.3.1)
    4. /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
    5. /System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility version 1.0.0, current version 1.0.0)
    6. /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 56.0.0)
    7. /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
    To copy to clipboard, switch view to plain text mode 

    otool -l

    (but, actually, there is not LC_RPATH section)

    Qt Code:
    1. Load command 0
    2. cmd LC_SEGMENT_64
    3. cmdsize 72
    4. segname __PAGEZERO
    5. vmaddr 0x0000000000000000
    6. vmsize 0x0000000100000000
    7. fileoff 0
    8. filesize 0
    9. maxprot 0x00000000
    10. initprot 0x00000000
    11. nsects 0
    12. flags 0x0
    13. Load command 1
    14. cmd LC_SEGMENT_64
    15. cmdsize 712
    16. segname __TEXT
    17. vmaddr 0x0000000100000000
    18. vmsize 0x00000000001ed000
    19. fileoff 0
    20. filesize 2019328
    21. maxprot 0x00000007
    22. initprot 0x00000005
    23. nsects 8
    24. flags 0x0
    25. Section
    26. sectname __text
    27. segname __TEXT
    28. addr 0x0000000100002690
    29. size 0x000000000016196a
    30. offset 9872
    31. align 2^4 (16)
    32. reloff 0
    33. nreloc 0
    34. flags 0x80000400
    35. reserved1 0
    36. reserved2 0
    37. Section
    38. sectname __stubs
    39. segname __TEXT
    40. addr 0x0000000100163ffa
    41. size 0x00000000000015de
    42. offset 1458170
    43. align 2^1 (2)
    44. reloff 0
    45. nreloc 0
    46. flags 0x80000408
    47. reserved1 0 (index into indirect symbol table)
    48. reserved2 6 (size of stubs)
    49. Section
    50. sectname __stub_helper
    51. segname __TEXT
    52. addr 0x00000001001655d8
    53. size 0x0000000000001c8a
    54. offset 1463768
    55. align 2^2 (4)
    56. reloff 0
    57. nreloc 0
    58. flags 0x80000400
    59. reserved1 0
    60. reserved2 0
    61. Section
    62. sectname __gcc_except_tab
    63. segname __TEXT
    64. addr 0x0000000100167264
    65. size 0x000000000003ba30
    66. offset 1471076
    67. align 2^2 (4)
    68. reloff 0
    69. nreloc 0
    70. flags 0x00000000
    71. reserved1 0
    72. reserved2 0
    73. Section
    74. sectname __const
    75. segname __TEXT
    76. addr 0x00000001001a2ca0
    77. size 0x000000000001b608
    78. offset 1715360
    79. align 2^4 (16)
    80. reloff 0
    81. nreloc 0
    82. flags 0x00000000
    83. reserved1 0
    84. reserved2 0
    85. Section
    86. sectname __cstring
    87. segname __TEXT
    88. addr 0x00000001001be2a8
    89. size 0x000000000000c4e6
    90. offset 1827496
    91. align 2^0 (1)
    92. reloff 0
    93. nreloc 0
    94. flags 0x00000002
    95. reserved1 0
    96. reserved2 0
    97. Section
    98. sectname __unwind_info
    99. segname __TEXT
    100. addr 0x00000001001ca78e
    101. size 0x0000000000003cc4
    102. offset 1877902
    103. align 2^0 (1)
    104. reloff 0
    105. nreloc 0
    106. flags 0x00000000
    107. reserved1 0
    108. reserved2 0
    109. Section
    110. sectname __eh_frame
    111. segname __TEXT
    112. addr 0x00000001001ce458
    113. size 0x000000000001eba8
    114. offset 1893464
    115. align 2^3 (8)
    116. reloff 0
    117. nreloc 0
    118. flags 0x00000000
    119. reserved1 0
    120. reserved2 0
    121. Load command 2
    122. cmd LC_SEGMENT_64
    123. cmdsize 792
    124. segname __DATA
    125. vmaddr 0x00000001001ed000
    126. vmsize 0x0000000000198000
    127. fileoff 2019328
    128. filesize 57344
    129. maxprot 0x00000007
    130. initprot 0x00000003
    131. nsects 9
    132. flags 0x0
    133. Section
    134. sectname __program_vars
    135. segname __DATA
    136. addr 0x00000001001ed000
    137. size 0x0000000000000028
    138. offset 2019328
    139. align 2^3 (8)
    140. reloff 0
    141. nreloc 0
    142. flags 0x00000000
    143. reserved1 0
    144. reserved2 0
    145. Section
    146. sectname __got
    147. segname __DATA
    148. addr 0x00000001001ed028
    149. size 0x00000000000001f0
    150. offset 2019368
    151. align 2^3 (8)
    152. reloff 0
    153. nreloc 0
    154. flags 0x00000006
    155. reserved1 933 (index into indirect symbol table)
    156. reserved2 0
    157. Section
    158. sectname __nl_symbol_ptr
    159. segname __DATA
    160. addr 0x00000001001ed218
    161. size 0x0000000000000010
    162. offset 2019864
    163. align 2^3 (8)
    164. reloff 0
    165. nreloc 0
    166. flags 0x00000006
    167. reserved1 995 (index into indirect symbol table)
    168. reserved2 0
    169. Section
    170. sectname __la_symbol_ptr
    171. segname __DATA
    172. addr 0x00000001001ed228
    173. size 0x0000000000001d28
    174. offset 2019880
    175. align 2^3 (8)
    176. reloff 0
    177. nreloc 0
    178. flags 0x00000007
    179. reserved1 997 (index into indirect symbol table)
    180. reserved2 0
    181. Section
    182. sectname __mod_init_func
    183. segname __DATA
    184. addr 0x00000001001eef50
    185. size 0x0000000000000070
    186. offset 2027344
    187. align 2^3 (8)
    188. reloff 0
    189. nreloc 0
    190. flags 0x00000009
    191. reserved1 0
    192. reserved2 0
    193. Section
    194. sectname __const
    195. segname __DATA
    196. addr 0x00000001001eefc0
    197. size 0x0000000000008f38
    198. offset 2027456
    199. align 2^4 (16)
    200. reloff 0
    201. nreloc 0
    202. flags 0x00000000
    203. reserved1 0
    204. reserved2 0
    205. Section
    206. sectname __data
    207. segname __DATA
    208. addr 0x00000001001f7f00
    209. size 0x00000000000023fc
    210. offset 2064128
    211. align 2^4 (16)
    212. reloff 0
    213. nreloc 0
    214. flags 0x00000000
    215. reserved1 0
    216. reserved2 0
    217. Section
    218. sectname __common
    219. segname __DATA
    220. addr 0x00000001001fa300
    221. size 0x000000000018a650
    222. offset 0
    223. align 2^4 (16)
    224. reloff 0
    225. nreloc 0
    226. flags 0x00000001
    227. reserved1 0
    228. reserved2 0
    229. Section
    230. sectname __bss
    231. segname __DATA
    232. addr 0x0000000100384950
    233. size 0x00000000000000d3
    234. offset 0
    235. align 2^4 (16)
    236. reloff 0
    237. nreloc 0
    238. flags 0x00000001
    239. reserved1 0
    240. reserved2 0
    241. Load command 3
    242. cmd LC_SEGMENT_64
    243. cmdsize 72
    244. segname __LINKEDIT
    245. vmaddr 0x0000000100385000
    246. vmsize 0x0000000000068000
    247. fileoff 2076672
    248. filesize 422208
    249. maxprot 0x00000007
    250. initprot 0x00000001
    251. nsects 0
    252. flags 0x0
    253. Load command 4
    254. cmd LC_DYLD_INFO_ONLY
    255. cmdsize 48
    256. rebase_off 0
    257. rebase_size 0
    258. bind_off 2076672
    259. bind_size 9104
    260. weak_bind_off 2085776
    261. weak_bind_size 17032
    262. lazy_bind_off 2102808
    263. lazy_bind_size 28928
    264. export_off 2131736
    265. export_size 104432
    266. Load command 5
    267. cmd LC_SYMTAB
    268. cmdsize 24
    269. symoff 2240112
    270. nsyms 5129
    271. stroff 2329896
    272. strsize 168984
    273. Load command 6
    274. cmd LC_DYSYMTAB
    275. cmdsize 80
    276. ilocalsym 0
    277. nlocalsym 1217
    278. iextdefsym 1217
    279. nextdefsym 3072
    280. iundefsym 4289
    281. nundefsym 840
    282. tocoff 0
    283. ntoc 0
    284. modtaboff 0
    285. nmodtab 0
    286. extrefsymoff 0
    287. nextrefsyms 0
    288. indirectsymoff 2322176
    289. nindirectsyms 1930
    290. extreloff 0
    291. nextrel 0
    292. locreloff 0
    293. nlocrel 0
    294. Load command 7
    295. cmd LC_LOAD_DYLINKER
    296. cmdsize 32
    297. name /usr/lib/dyld (offset 12)
    298. Load command 8
    299. cmd LC_UUID
    300. cmdsize 24
    301. uuid 02E85858-CABA-39C5-A01A-FB2AE1929C24
    302. Load command 9
    303. cmd LC_VERSION_MIN_MACOSX
    304. cmdsize 16
    305. version 10.6
    306. sdk 10.8
    307. Load command 10
    308. cmd LC_UNIXTHREAD
    309. cmdsize 184
    310. flavor x86_THREAD_STATE64
    311. count x86_THREAD_STATE64_COUNT
    312. rax 0x0000000000000000 rbx 0x0000000000000000 rcx 0x0000000000000000
    313. rdx 0x0000000000000000 rdi 0x0000000000000000 rsi 0x0000000000000000
    314. rbp 0x0000000000000000 rsp 0x0000000000000000 r8 0x0000000000000000
    315. r9 0x0000000000000000 r10 0x0000000000000000 r11 0x0000000000000000
    316. r12 0x0000000000000000 r13 0x0000000000000000 r14 0x0000000000000000
    317. r15 0x0000000000000000 rip 0x0000000100002690
    318. rflags 0x0000000000000000 cs 0x0000000000000000 fs 0x0000000000000000
    319. gs 0x0000000000000000
    320. Load command 11
    321. cmd LC_LOAD_DYLIB
    322. cmdsize 96
    323. name @loader_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets (offset 24)
    324. time stamp 2 Thu Jan 1 01:00:02 1970
    325. current version 5.3.1
    326. compatibility version 5.3.0
    327. Load command 12
    328. cmd LC_LOAD_DYLIB
    329. cmdsize 88
    330. name @loader_path/../Frameworks/QtGui.framework/Versions/5/QtGui (offset 24)
    331. time stamp 2 Thu Jan 1 01:00:02 1970
    332. current version 5.3.1
    333. compatibility version 5.3.0
    334. Load command 13
    335. cmd LC_LOAD_DYLIB
    336. cmdsize 88
    337. name @loader_path/../Frameworks/QtCore.framework/Versions/5/QtCore (offset 24)
    338. time stamp 2 Thu Jan 1 01:00:02 1970
    339. current version 5.3.1
    340. compatibility version 5.3.0
    341. Load command 14
    342. cmd LC_LOAD_DYLIB
    343. cmdsize 88
    344. name /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (offset 24)
    345. time stamp 2 Thu Jan 1 01:00:02 1970
    346. current version 1.0.0
    347. compatibility version 1.0.0
    348. Load command 15
    349. cmd LC_LOAD_DYLIB
    350. cmdsize 80
    351. name /System/Library/Frameworks/AGL.framework/Versions/A/AGL (offset 24)
    352. time stamp 2 Thu Jan 1 01:00:02 1970
    353. current version 1.0.0
    354. compatibility version 1.0.0
    355. Load command 16
    356. cmd LC_LOAD_DYLIB
    357. cmdsize 56
    358. name /usr/lib/libstdc++.6.dylib (offset 24)
    359. time stamp 2 Thu Jan 1 01:00:02 1970
    360. current version 56.0.0
    361. compatibility version 7.0.0
    362. Load command 17
    363. cmd LC_LOAD_DYLIB
    364. cmdsize 56
    365. name /usr/lib/libSystem.B.dylib (offset 24)
    366. time stamp 2 Thu Jan 1 01:00:02 1970
    367. current version 169.3.0
    368. compatibility version 1.0.0
    369. Load command 18
    370. cmd LC_FUNCTION_STARTS
    371. cmdsize 16
    372. dataoff 2236168
    373. datasize 3944
    374. Load command 19
    375. cmd LC_DATA_IN_CODE
    376. cmdsize 16
    377. dataoff 2240112
    378. datasize 0
    To copy to clipboard, switch view to plain text mode 

  10. #9
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Calling external programs via QProcess on Mac OS

    I am not entirely sure this will help, but when macdeployqt is run on my system, my binary in the app bundle winds up with the Qt libraries specified as:

    Qt Code:
    1. @rpath/Sparkle.framework/Versions/A/Sparkle (compatibility version 1.6.0, current version 1.8.0)
    2. /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1265.21.0)
    3. @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets (compatibility version 5.3.0, current version 5.3.2)
    4. @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui (compatibility version 5.3.0, current version 5.3.2)
    5. @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore (compatibility version 5.3.0, current version 5.3.2)
    6. @executable_path/../Frameworks/QtConcurrent.framework/Versions/5/QtConcurrent (compatibility version 5.3.0, current version 5.3.2)
    7. @executable_path/../Frameworks/QtNetwork.framework/Versions/5/QtNetwork (compatibility version 5.3.0, current version 5.3.2)
    8. /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
    9. /System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility version 1.0.0, current version 1.0.0)
    10. /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
    11. /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
    12. /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 855.17.0)
    13. /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1056.16.0)
    14. /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
    To copy to clipboard, switch view to plain text mode 

    Can you try using the following linker flags and see if the behavior works for you?

    Qt Code:
    1. QMAKE_LFLAGS += -Wl,-install_name,@executable_path/../Frameworks
    To copy to clipboard, switch view to plain text mode 

    Not sure it will help your situation, but I've never used @loader_path, so might be worth a shot...

    Regards,

    Jeff

  11. #10
    Join Date
    May 2009
    Location
    Berlin
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Calling external programs via QProcess on Mac OS

    I just installed Qt 5.4.0 and rebuilt everything. Now the output after applying macdeployqt is slightly different:

    Qt Code:
    1. @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets (compatibility version 5.4.0, current version 5.4.0)
    2. @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui (compatibility version 5.4.0, current version 5.4.0)
    3. @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore (compatibility version 5.4.0, current version 5.4.0)
    4. /System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration (compatibility version 1.0.0, current version 1.0.0)
    5. /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
    6. /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
    7. /System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility version 1.0.0, current version 1.0.0)
    8. /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 56.0.0)
    9. /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
    To copy to clipboard, switch view to plain text mode 

    Now it's also using @executable_path, but when I start the bundle by double-clicking, the program still cannot call external programs. I tried something I didn't before and ran the bundle from the shell with "open Foo.app" and being started like that, the program can do everything. So, it's definitely the execution enviroment. When I use MuCommander to browse the bundle for the binary, that is hidden inside, and run that, then it also opens a shell window and everything is fine.

    Somehow I have to find out how to spawn a shell execution environment when running a bundle.

    Maybe that article points to the right direction: http://stupidpythonideas.blogspot.de...variables.html

    On OS X, Finder.app is a child of your launchd session, which is a child of the root launchd session, which is process 0. There's no shell anywhere. And when you double-click an app, it asks LaunchServices to run the app. So, your app doesn't inherit anything from Finder, and even if it did, Finder hasn't inherited anything from your login shell.
    He suggests defining an environment in the plist file with the LSEnvironment key. The question is, what has to be there in order to mimick a shell environment. Can be quite a lot I guess.
    Last edited by berliner; 11th December 2014 at 00:52.

  12. #11
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Calling external programs via QProcess on Mac OS

    Quote Originally Posted by berliner View Post
    Somehow I have to find out how to spawn a shell execution environment when running a bundle.
    A couple of things I forgot to ask up front (and probably should have):

    1) Have you tried to start the QProcess with the fully qualified path for latex? i.e. /usr/local/bin/latex (or wherever it is installed)

    2) Run otool -L latex to see what external library dependencies latex may have. If unable to load, the start would fail, etc.

    3) I don't have latex installed on my mac, but can you confirm it's a binary executable by running "file latex"? Should show as Mach-O 64-bit executable x86_64. On the off chance that it's a shell script, I believe you have to run the shell scripts by starting the program "sh" or "bash" (or whatever shell you use) and pass latex as the first parameter to the QProcess start (i.e. "sh latex", etc)

    Look forward to your responses, I'm curious to understand why this isn't working because in my usage, I had no problems at all running external processes using QProcess. One difference I do notice is that you seem to be using the start method that takes the program and all arguments as one QString. In my case, use use the overload that takes a QString for the program to start and a QStringList that contains all of the program arguments. I'm using ffmpeg, which takes a lot of arguments, so that's why I chose that overload, but might be worth a try for you to do the same.

  13. #12
    Join Date
    May 2009
    Location
    Berlin
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Calling external programs via QProcess on Mac OS

    Ok, I tried running latex and gs with full paths and that is working.

    I just don't understand why it didn't work with just adding the paths to the PATH variable by modifying the variable list as you suggested.

    I add /usr/texbin and /usr/local/bin and I confirm that both have been added by printing the whole string list.

    original
    PATH=/Applications/Qt5.4.0/5.4/clang_64/bin:/usr/bin:/bin:/usr/sbin:/sbin

    modifed
    PATH=/usr/texbin:/usr/local/bin:/Applications/Qt5.4.0/5.4/clang_64/bin:/usr/bin:/bin:/usr/sbin:/sbin

    Then I apply it to the process by using setEnvironment(...) right before calling process.start(). Should be working, but isn't. I think I will now extend the commands with the full path and give the user an option to configure that path via the program settings.


    Added after 1 40 minutes:


    Could it actually be an error in thinking? I don't have to change the environment of the new process but of the current process? Because this is the one that wants to start the program.
    Last edited by berliner; 14th December 2014 at 01:07.

  14. #13
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Calling external programs via QProcess on Mac OS

    Quote Originally Posted by berliner View Post
    Could it actually be an error in thinking? I don't have to change the environment of the new process but of the current process? Because this is the one that wants to start the program.
    I think you hit the nail on the head, and here's why it was working for me w/o any issues. I do get the fully qualified path to the ffprobe and ffmpeg executables via a user preferences dialog that uses QSettings.

    In my method that reads user prefs via QSettings, I add "/opt/local/bin:/usr/local/bin" to the path for QProcess, and I actually run a "which" command with ffprobe and ffmpeg as arguments to the "which" command so that I can have a default value for the QSettings for ffprobe and ffmpeg. If I do not update the PATH before running "which", it fails to find ffprobe and ffmpeg, because as you have pointed out, my gui app running from the bundle still has the default path.

    So, you may want to try something similar, update your path to contain the directories you want, then start a QProcess for "which latex". The output of that QProcess will contain the full path to latex, etc.

    Glad you raised that question, because I it was bugging me...

    Good luck,

    jthomps

  15. #14
    Join Date
    May 2009
    Location
    Berlin
    Posts
    14
    Thanks
    1
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Calling external programs via QProcess on Mac OS

    I have one more take on that.

    The Apple developer docs describe how to set env variables through the Info.plist file by adding an LSEnvironment section.

    I added that to Info.plist:

    Qt Code:
    1. <key>LSEnvironment</key>
    2. <dict>
    3. <key>PATH</key>
    4. <string>/usr/texbin:/usr/local/bin</string>
    5. </dict>
    To copy to clipboard, switch view to plain text mode 

    ...but it didn't work. I also tried <string>$PATH:/usr/texbin:/usr/local/bin</string> and some other variants, including adding some arbitrarily named variables just to see if ANYTHING will be added to the environment. No it didn't. I googled around and it seems that others ran into the same problem. It just doesn't seem to be working as promised by Apple.

    I found something else that works and that is modifying the PATH with good old C funcion
    Qt Code:
    1. int setenv(const char *name, const char *value, int overwrite);
    To copy to clipboard, switch view to plain text mode 

    So, my code looks like that now:

    Qt Code:
    1. void setMacEnvironment()
    2. {
    3. QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    4. QStringList envlist = env.toStringList();
    5.  
    6. for(int i=0; i < envlist.size(); i++)
    7. {
    8. QString entry = envlist[i];
    9.  
    10. if(entry.startsWith("PATH="))
    11. {
    12. int index = entry.indexOf("=");
    13.  
    14. if(index != -1)
    15. {
    16. QString value = entry.right(entry.length() - (index+1));
    17. value += ":/usr/texbin:/usr/local/bin";
    18.  
    19. setenv("PATH", value.toLatin1().constData(), true);
    20. }
    21.  
    22. break;
    23. }
    24. }
    25. }
    To copy to clipboard, switch view to plain text mode 

    (ok can be more sophisticated using iterator instead of array subscript and string splitting by regular expression, but for me it's ok.)

    I will probably add a program setting that allows Mac users to set a string they want to be added to PATH. The default value will be "/usr/texbin:/usr/local/bin".

    Of course, I could also just call the external programs with their absolut paths, but setenv() has the advantage that the modified environment is inherited by these programs. If these again need to call something external, they will have the necessary PATH already set up. That is actually my case. My program calls latex and gs, but it also spawns another tool that again has to call gs. Then it comes in handy that my program already creates a working enviroment for all forks and forks of forks.

    One more little addition for Windows compatibility. The stdlib.h that ships with Visual Studio does not contain setenv(). I think that's because setenv is BSD and POSIX.1-2001, but Windows only implements POSIX.1 So I'm using the following:

    Qt Code:
    1. #ifdef WIN32
    2. SetEnvironmentVariable("PATH", value.toLatin1().constData());
    3. #else
    4. setenv("PATH", value.toLatin1().constData(), true);
    5. #endif;
    To copy to clipboard, switch view to plain text mode 

    Works for Visual Studio and probably for QtCreator when Visual Studio Express is used as the compiler.
    Last edited by berliner; 16th December 2014 at 00:30.

Similar Threads

  1. QProcess & Working with External Programs
    By jstippey in forum Qt Programming
    Replies: 2
    Last Post: 20th December 2010, 20:04
  2. [QProcess] Calling console program
    By bgarisn in forum Newbie
    Replies: 3
    Last Post: 25th February 2010, 15:11
  3. Calling external programs?
    By Hossie in forum Qt Programming
    Replies: 12
    Last Post: 17th May 2008, 17:19
  4. QProcess and console programs
    By bond_e in forum Qt Programming
    Replies: 10
    Last Post: 13th July 2007, 08:39
  5. How to communicate with external programs?
    By deekayt in forum Qt Programming
    Replies: 7
    Last Post: 27th October 2006, 23:01

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.