Linking Mac Frameworks using Premake and GNU Make - xcode

I have a "cross platform" application that uses two code repositories at the moment, maintained relatively independently, and built with VS / Xcode depending on the target platform (win or mac respectively). I fell in love with Premake after using it on a few previous projects and am trying to pull all of my code for this application together into a single cross-compilable codebase.
I don't want to rely on Xcode, and instead want any developer to be able to build on Mac using either Xcode or gmake. I have a non-standard framework that I want to link to and include in the repository (it won't be located in /Library/Frameworks or any of the default mac framework search paths). I've added the framework file in a directory in my project /lib/TheFramework.framework. My premake file contains the following under the project definition:
includedirs {".", "lib", "lib/TheFramework.framework/Headers"}
libdirs {"lib"}
links {"TheFramework.framework"}
When I compile, (running $ premake5 gmake and then $ make), I get a header file not found error. Is there something wrong with my search paths? Am I missing a path or a flag somewhere?
Thanks!

Before looking at what you need to do with premake, let's first look at what needs to happen under the hood.
When compiling a mac program with a non-standard framework on gcc or clang (which is what your resulting make file does) it is necessary to do two things:
Specify the name of the framework, via -framework TheFramework - This is what premake does when you provide it with links {"TheFramework.framework"
Specify the location of the framework, via -F /Path/To/Framework/ - This is currently not being handled automatically by premake.
I've made a simple test c program that uses the SDL2 framework and compiled it with gcc: https://gist.github.com/JohannesMP/6ff3463482ebbdc82c2e - notice how when I leave off the -F /... flag I get an error that is probably similar to what you described.
So what is happening is, although you are providing premake with the include dir, premake will not add that the proper -F flag.
One way around this is to do the following:
configuration {"macosx", "gmake"}
buildoptions {"-F /Path/To/Framework"}
linkoptions {"-F /Path/To/Framework"}
(See here for an example project: https://gist.github.com/JohannesMP/9a9b5263c127103f1861#file-premake5-lua-L24-L26 )
In premake5 this will blindly append the code provided to both the build step as well as the link step. It is necessary to do it both for build as well as link.
Just keep in mind that, because premake doesn't process or check the build/link options for being valid, a user will receive an error if the provided path doesn't exist on their machine. For example while you might have a framework in your user-specific directory ~/Library/Frameworks, since that folder doesn't exist by default another user might be using the global /Library/Frameworks instead, and when they try to compile your premake project with gmake they will get a warning:
ld: warning: directory not found for option '-F/Users/<NAME>/Library/Frameworks'
At this point, it seems that there is no 'safe' way to get premake5 to try to include the framework path, but that may change in the future.
Check out this issue I posted on the premake repo: https://github.com/premake/premake-core/issues/196

Related

Xcode use different Bison

I'm using Bison and Flex in an Xcode project. I didn't want to put the generated files under source control, so I was happy to find that Xcode natively supports Bison/Flex files, generating the parsers on-the-fly in its derived data folder. So far so good.
However, Xcode uses an embedded old Bison version (2.3):
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/yacc
which doesn't yet support the %define api.pure full directive. Since this bison executable is under the Xcode.app bundle I can't replace it, so I installed the latest version via Brew and added it to my $PATH through ~/.bash_profile (~/.bashrc also sources my bash profile). So in bash I can say:
$ which bison
/usr/local/Cellar/bison/3.0.4/bin//bison
However, Xcode still uses it's own version... I suppose the path to the internal bison is hardcoded.
My second approach was to create a custom build rule for Yacc files, and run the correct version of bison from there. This time the problem was that as Xcode ran my custom build rule, it immediately tried to build the resulting C files. The generated C files would however depend on the header file yet to be generated by Flex, because that's where e.g. yyscan_t is declared (used by Bison in the generated C file). But on the other hand, Flex-generated C files also include the Bison-generated header, so compiling with Flex first doesn't help...
What I need is to first only generate the Flex and Bison headers/sources and then build them along with the rest of the project.
How can I achieve this?
I've managed to solve the issue by putting the *.l and *.y files under a *.parser folder and adding that folder to the project. Then I removed the *.l and *.y files added the folder to the compiled sources:
And then made a Build Rule for *.parser like this:
This enables me to first run yacc and lex and only then will the resulting *.cpp files be passed to the compilation step.
If you go to your build target, Build Phases, and click the + on the bar with the search box on it, you can add a New Run Script Phase. You can then drag that above your current Compile Sources phase. You can do whatever you want in that script phase, and it will run before compilation starts.
This is a bit of a Zombie, but if I ever come back here again, I will want to see the answer.
Certainly from XCode 12 (probably before) the answer is trivially easy.
(1) Go to build settings
(2a) Press the + for a brand new setting variable.
(2b) Change the NAME to YACC, and it's VALUE to /usr/local/bin/bison (or whatever path you need for brew).
(3a) Press the + for a brand new setting variable.
(3b) Change the NAME to LEX, and it's VALUE to /usr/local/bin/flex (or whatever path you need for brew).
(4+) use the YACC/LEX settings for flags that you want to use.
I've managed to do it with custom build rules, using bison installed from brew and flex that comes with macOS, not the one bundled with Xcode. I'm not sure if my problem was the same as yours, but if you want to take a look my project is on GitHub.

Xcode warning with non-standard Framework ld: warning: directory not found for option -F

Cleaning up warnings, I could see the following:
ld: warning: directory not found for option '-F/myPath/etc/myframework'
This was happening with non-standard iOS frameworks. How to eliminate the warning?
Checking the man page of the linker ld shows the following detail for the -Fdir option:
Add dir to the list of directories in which to search for frameworks.
Directories specified with -F are searched in the
order they appear on the command line and before the default search path. In Xcode4 and later, there can be a space
between the -F and directory.
Sure enough, checking the project.pbxproj showed the missing folder:
FRAMEWORK_SEARCH_PATHS = (
"\"$(SDKROOT)/Developer/Library/Frameworks\"",
"\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"",
"\"myPath/etc/myframework\"",
);
So, I thought the whole deal with frameworks was that they avoided all this hassle. Well, that's true for standard frameworks, i.e. the SDK ones. For anything else, more tweakery is required. From Framework Programming Guide:
Locating Frameworks in Non-Standard Directories
If your project links to frameworks that are not included in any of
the standard locations, you must explicitly specify the location of
that framework before Xcode can locate its header files. To specify
the location of such a framework, add the directory containing the
framework to the “Framework Search Paths” option of your Xcode
project. Xcode passes this list of directories to the compiler and
linker, which both use the list to search for the framework resources.
Note: The standard locations for frameworks are the
/System/Library/Frameworks directory and the /Library/Frameworks
directory on the local system.
Turns out in Xcode's Build Settings, there is a specific entry for Framework Search Paths.
Adding the generic catch-all entry of $(SRCROOT) as per the answer to this question did the business and eliminated the warnings. Oh, and don't forget to set the drop down to "Recursive".

Adding library to Xcode project

I'd like to add the libevent library to my Xcode project. I want to include it in the executable, because libevent isn't installed by default on Mac OS X.
I can compile the library from source using ./configure && make. I expected to find a .a library file, but there isn't. What do I do then? What files are relevant and how do I add them to Xcode?
Sorry for this very basic question, but I don't even know where to start.
First off, let's find out if your library truly got built. In the terminal, type in cd / and then find . -name libevent\* -print and see if the path for your libevent.a file actually appears.
If you can't find it, try running sudo make install from the top level of the library source code and then the library may end up getting installed in /usr/local/lib or some other appropriate place.
Once you do find the library, you can drag & drop it into your Project's list of Files in Xcode. Or you can include -levent in the link settings for your project.
Note that Xcode has this nasty "feature" that if it sees both dynamic and static versions of a library, it will always link against the dynamic one, even you specify the static one (.a) in your project. There's no way to override this "feafure" and you have to move or delete the dynamic one out of the library search paths.

USB GCC Development Environment with Libraries

I'm trying to get something of an environment on a usb stick to develop C++ code in. I plan to use other computers, most of the time linux, to work on this from a command line using g++ and make.
The problem is I need to use some libraries, like Lua and OpenGL, which the computers don't have. I cannot add them to the normal directories, I do not have root on these computers. Most of the solutions I've found involve putting things in /usr/lib/ and the like, but I cannot do that. I've also attempted adding options like '-L/media//lib', which is where they are kept, and it didn't work. When compiling, I get the same errors I got when first switching to an OS with the libraries not installed.
Is there somewhere on the computer outside of /usr/ I can put them, or a way to make gcc 'see' them?
You need more than the libraries to be able to compile code utilizing those libraries. (I'm assuming Linux here, things might be slightly different on e.g. OSX,BSDs,Cygwin,Mingw..)
Libraries
For development you need these 3 things when your code uses a library:
The library header files, .h files
The library development files, libXXX.so or libXXX.a typically
The library runtime files , libXXX.so.Y where Y is a version number. These are not needed if you statically link in the library.
You seem to be missing the header files (?) Add them to your usb stick, say under /media/include
Development
Use (e.g.) the compiler flag -I/media/include when compiling source code to refer to a non-standard location of header files.
Use the compiler/linker flag -L/media/lib to refer to non-standard location of libraries.
You might be missing the first step.
Running
For dynamically linked libraries, the system will load those only from default locations, typically /lib/ , /usr/lib/
Learn the ldd tool to help debug this step.
You need to tell the system where to load additional libraries when you're running a program, here's 3 alternatives:
Systemwide: Edit /etc/ld.so.conf and add /media/libs there. Run ldconfig -a afterwards.
Local, to the current shell only. set the LD_LIBRARY_PATH environment variable to refer to /media/lib, run export LD_LIBRARY_PATH=/media/lib
Executable: Hardcode the non-standard library path in the executable. You add this to the linking step when creating your executable: -Wl,-rpath,/media/lib
Etc.
There could be other reasons things are not working out, if so,
show us the output of ls -l /media/libs , and where you put the library header files, the command line you use to compile/link, and the exact errors you get.
Missing the headers and/or development libraries (for dynamic libraries there is usually a symlink from a libXXX.so to a libXXX.so.Y , the linker needs the libXXX.so , it will not look directly at libXXX.so.Y)
using libraries not compatible with your current OS/architecture. (libraries compiled on one linux distro is often not compatible with another distro, or even another minor version of the same distro)
using an usb stick with a FAT32 filesystem, you'll get in trouble with symlinks..

setting up qt for xcode debugging

I just installed QT 4.6 on snow leopard 10.6.3. I wrote a really simple program. I can generate a xcode project using qmake, but I can't step into QT function. How can I set it up?
By default, qt is built with a debug and a non-debug library. This is my understanding. For example,
% ls /Library/Frameworks/QtCore.framework/
Contents/ Headers# QtCore# QtCore.prl QtCore_debug# QtCore_debug.dSYM/ QtCore_debug.prl Versions/
Also, my default from source build of Qt 4.7 branch also has the *_debug libs.
Setting up for Xcode is cake, you just set up your project and
% qmake -spec macx-xcode
This -spec is the default for the official mac distribution, but if you build your own from source the default is macx-g++ which creates a Makefile project.
This generates a MyProject.xcodeproj that comes preconfigured to link all the necessary Qt frameworks, sets up paths, and has a Release and Debug build target set to the same options as the official SDK's.
This is all assuming you have your qt project file set up, if you need to generate that first from a raw source directory:
% qmake -project
Debugging works "out of the box" for these generated *.xcodeproj files. However, there's one little "hitch". Since Qt is full of custom data types, Xcode doesn't know how to display their "values" in the debugger's summary pane. So you can't see what value a QString has, for example.
There's a method of entering custom macros for display, but I've found these often (always?) don't work for QObjects.
To get that working, I've started a project that uses xcode's debugger c callbacks (also mentioned in the above linked article, though their example doesn't even work o.O). I call it Qt4DataFormatters.
I've just started it and have been adding types as the need arises. It's dirt simple to create one using the existing functions as a template though.
I haven't tried this on Mac, but on Linux you need to take the following process:
First, you need to setup Qt so that it has debugging symbols available to you:
./configure -debug-and-release separate-debug-info # other options
With the debugging symbols available, you should now be able to get valid stack traces.
When building your application with qmake, you need to have the debug (or debug_and_release) flag set in your project file:
CONFIG += debug
Once you've done that, you should only need to tell the debugger where the Qt source is located:
(gdb) dir /path/to/qt/src
After that, list should show you the actual Qt source code. You may need to add additional directories under the src directory for the debugger to pick it all up.

Resources