Xcode: define preprocessor macro in one project used by another project - objective-c

I have multiple app projects which all link to the same static library project. Each app project needs to compile the static library project using different settings.
At the moment I have a conditional compilation header in the static library project, let's call it ViewType.h which adds more types, typedefs, macros, etc specific to each view.
#define VIEW_A 1
#define VIEW_B 2
#define VIEW_C 3
#ifndef VIEWTYPE
#define VIEWTYPE VIEW_A
#endif
#if VIEWTYPE == VIEW_A
// further typedefs and defines tailored to VIEW_A
#elif VIEWTYPE == VIEW_B
// further typedefs and defines tailored to VIEW_B
#elif VIEWTYPE == VIEW_C
// further typedefs and defines tailored to VIEW_C
#endif
The problem here is that each app project needs to change the VIEWTYPE in the static library project, and every time I switch app projects I have to change the VIEWTYPE again.
Unfortunately it seems I can not define VIEWTYPE=2 (for example) as preprocessor macro in the app target. And I can't define this in the static library project either because all 3 projects include the same static library project, because the .xcodeproj is shared between the 3 apps (ie the .xcodeproj is dragged & dropped onto the app project; I'm not using a workspace).
I understand one issue is that the static library being a dependent target it is built first before the app target is even considered. So perhaps there's some way to make that decision which app the library is built for based on other conditionals (ie checking for a file, or including an optional app-specific header).
Question: How I can create a macro or otherwise perform conditional compilation based on macros/settings defined by the app target which are then adhered to by the static library project?

The first, simplest approach, is to get rid of the static library, and just include the source files directly into the dependent projects. I often find that intermediate static libraries are much more trouble than they're worth. Their one big benefit comes when they provide a significant build-performance improvement, but they can't here since you're rebuilding the static library for every final target anyway.
I will say that the use of a type #defines almost always makes me cry, and may suggest a design flaw that could be better handled. For instance, you may want to implement methods that return the class required (the way UIView layerClass does). Pre-processor trickery that changes type definitions can lead to extremely subtle bugs. (I just chased down a case of this last year… it was a horrible, horrible crash to figure out.)
That said, another approach for certain versions of this problem can be solved with xcconfig files. For example, if there are actually multiple copies of the static library (i.e. this is a library that is commonly copied into other projects), then you can use an xcconfig file that has an #include "../SpecialTypeDefs.xcconfig". That file would be provided by each project to set special declarations. Failure to define that file would lead to a complier error, so it's easy to not have an error.
But personally, I'd just include the files into the actual project directly and skip the library unless they're really enormous.

Related

Is it possible to prevent POSIX symbol name pollution in Objective-C?

I've run into a somewhat unexpected behavior in Xcode/Objective-C. I know it's probably not advised, but if I want to make my own struct in_addr in a .m file, it seems I can't. This implies something rather strange about namespaces and symbol pollution in Objective-C. The same seems to apply for many other networking types and perhaps other POSIX-y things as well.
I came up with a very basic example that demonstrates this behavior. Note that this snippet is the entire contents of the .m file.
#define _SYS_SOCKET_H_
#define _NETINET_IN_H_
#include <stdint.h>
struct in_addr {
uint32_t foo;
};
which yields the build error Redefinition of 'in_addr'.
This implies some fairly strange things about Objective-C. For starters, I wouldn't expect <stdint.h> to bring in any networking types. But even allowing that it might, defining _NETINET_IN_H_ first should prevent the definition of struct in_addr. And yet even still, this code refuses to build.
Is it possible to somehow forgo this forced symbol visibility? Is there a list of symbols that are included, no matter what? Is there a good reason for this behavior?
edit: Stranger still, if i remove <stdint.h> and change the uint32_t to int, this actually does compile.
If you go into the Report navigator and read the full error emitted by the clang tool, you'll see a big hint:
In module 'Darwin' imported from /Users/csrstka/Desktop/asdfasdf/asdfasdf/main.m:1:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/netinet/in.h:302:12: note: field has name 's_addr' here
in_addr_t s_addr;
As you can see, the existing in_addr is coming from the Darwin module, which is implicitly imported due to your #include of stdint.h, which is part of the Darwin module. You can see this if you go to Product > Perform Action > Preprocess in Xcode—instead of copying in all the headers you've imported, there's just one line about importing Darwin.C.stdint.
Basically, there are a few purposes for modules; they improve compile times by cutting down on redundant compilation tasks, and they prevent people from messing with library headers via #defines like you're trying to do. ;-) For more on Objective-C modules, how they work, and the rationale behind them, see this link:
https://clang.llvm.org/docs/Modules.html#introduction
Of particular interest to your question are the following excerpts:
The primary user-level feature of modules is the import operation, which provides access to the API of software libraries. However, today’s programs make extensive use of #include, and it is unrealistic to assume that all of this code will change overnight. Instead, modules automatically translate #include directives into the corresponding module import. For example, the include directive
#include <stdio.h>
will be automatically mapped to an import of the module std.io. Even with specific import syntax in the language, this particular feature is important for both adoption and backward compatibility: automatic translation of #include to import allows an application to get the benefits of modules (for all modules-enabled libraries) without any changes to the application itself. Thus, users can easily use modules with one compiler while falling back to the preprocessor-inclusion mechanism with other compilers.
And later on:
If any submodule of a module is imported into any part of a program, the entire top-level module is considered to be part of the program. As a consequence of this, Clang may diagnose conflicts between an entity declared in an unimported submodule and an entity declared in the current translation unit, and Clang may inline or devirtualize based on knowledge from unimported submodules.
Or, if you'd prefer to turn them off and get more traditional C-like behavior, you can simply set Enable Modules (C and Objective-C) to No in Xcode's Build Settings, or compile without the -fmodules flag if you're using the command line.

Exporting template classes c++

The following is my scenario:
I have an executable along with multiple shared libraries(.dll or .so). Both the executable and the shared libraries(.dll or .so) uses a set of common libraries. Since they are common libraries I want to reduce the binary foot print of the shared libraries, in order to reduce the shared library's foot print I am exporting the contents of the common libraries from the executable and importing them in shared libraries(dll or .so).
Note: Though size of the foot print is not the only one among multiple reasons, for the time being we can stick with it being major reason.
Problem:
In the common libraries there are some inlined functions and some template classes. When I compile the executable and the shared libraries using performance optimization flags the inlined/ template classes are inlined both in executable and shared libraries. It will create problems if the inline definitions are modified and there are some shared libraries with different set of inline function definitions.
How to solve this problem ?
When I started thinking about this even the STL classes provided by the CRT are template classes. The similar problem exists even in their case. Have they solved this problem? What will happen if they modify the definition of std::vector ? Please help.
A class template is a mechanism for creating class. But these classed don't get instantiated until you define a particular instance of a class (with a template parameter.)
In your export control file.
#ifdef XXXX_BUILD
#define XXXX_EXPORT __declspec(dllexport)
#define XXXX_EXTERN
#else
#define XXXX_EXPORT __declspec(dllimport)
#define XXXX_EXTERN extern
#endif
where XXXX_BUILD is a symbol defined in your project.
To get your class exported.
XXXX_EXTERN template class XXXX_EXPORT YourClass<double>;
Where double is the type you want to instantiate the class with.
https://support.microsoft.com/en-us/help/168958/how-to-export-an-instantiation-of-a-standard-template-library-stl-clas

dllexport in headers confusion

I'm confused as to why __declspec(dllexport) or equivalent needs to go in the header file. Say I'm writing a library. Surely the users don't need to know or worry about whether symbols are exported or not, all they care about is that the function declarations are there and will presumably be linked against the shared or static library itself. So why can't all this boilerplate go into source files, for use only at build time?
The only use case I think of is a situation where someone is writing a wrapper of my library and needs to export all of my functions as well, but in general that is not the case - is it really worth the hassle of having all the export stuff inside public headers? Is there something I'm missing, is this a technical limitation of linkers..?
I'm asking because I like my headers and build system to be clean, and as dllexport stuff is generally set/not set based on whether we are building the library as a shared or static library, I find it strange that it should end up inside public headers since it's (to my understanding) fundamentally a build time concept. So can someone please enlighten me on what I am missing?
I'm not really sure I can provide a great answer. My impression is that it serves several purposes:
It speeds the loading of DLLs, particularly when lots of DLLs are used (because there are fewer exported symbols to search through)
It reduces the possibility of symbols colliding at run-time (because there are fewer exported symbols)
It allows the linker to complain about undefined symbols (instead of just assuming it might find them at run time.
I'm sure there are other reasons. I generally wrap my APIs in something like this:
#if defined(MY_LIB_CREATION)
#define MY_LIB_API __declspec(dllexport)
#else
#define MY_LIB_API __declspec(dllimport)
#endif
And then all of my API functions & classes are defined as MY_LIB_API:
class MY_LIB_API Foo {};
MY_LIB_API void bar();
And then in the project file defined MY_LIB_CREATION for the project implementing your library.

ObjC: How to compile static library that includes optional classes that depend on a third party library

I'm trying to find the best way to package a static library(lets call it Lib1) that includes an optional class(say, ClassA), which itself requires a second static library(Lib2). In other words, Lib2 is only needed if ClassA is referenced in the project's code. Things seem to work fine, unless Lib1 is used in a project that doesn't use ClassA(and hence does not include Lib2), but requires the -ObjC linker flag(because of other project dependencies, not mine).
I'm trying to come up with a an easy solution for the following three scenarios:
1) project includes my static lib, does NOT use the optional class, does not specify the -ObjC flag
2) project includes my static lib, does NOT use the optional class, but requires -ObjC flag
3) project includes my static lib + second static library, and DOES use the optional class (we don't care about the -ObjC flag at this point)
Is there a linker flag out there to strip my optional class out of the final project app so that it doesn't require the second static lib? I guess my other alternatives are to release multiple versions of my static lib, one that includes the option class(the standard choice), one that does not(the alternate, for projects with -ObjC requirements), or maybe supply a stub file, that supplies empty implementations of all the classes needed from the second static library? This seems like it could be a common problem in the static library world... is there a best practice for this scenario?
Thanks!
Solution:
1) Suggest to my -ObjC users that they use -force_load instead. (thanks Rob!)
2) For users that can't do 1, I'll have a alternate build that does not include ClassA
The best practice is always to have the final binary link all the static libs required. You should never bundle one static library into another. You should absolutely never bundle a well-known (i.e. open-source) static library into a static library you ship. This can create incredible headaches for the final consumer because they can wind up with multiple versions of the same code. Tracking down the bugs that can come from this is insanely difficult. If they're lucky, they'll just get confusing compiler errors. If they're unlucky, their code will behave in unpredictable ways and randomly crash.
Ship all the static libraries separately. Tell your clients which ones they need to link for various configurations. Trying to avoid this just makes their lives difficult.
Some other discussions that may be useful:
Duplicate Symbol Error: SBJsonParser.o? (Example of a customer who ran into a vendor doing this to him)
Linking static libraries, that share another static library
Why don't iOS framework dependencies need to be explicitly linked to a static library project or framework project when they do for an app project?
The -ObjC flag should be preventing the automatic stripping of ClassA entirely, whether its used or not (see TN1490 for more details).
If ClassA is never used except in certain circumstances and you want to save space, you should probably move ClassA into its own static library. Or use #ifdef to conditionally compile it.
Alternately, you can remove the -ObjC flag and use -force_load to individually load any category-only compile units (which is the problem -ObjC is used to address).

import = dynamic linking? & include = static linking?

I wonder the difference of import and include in Object-c
By the way, I am not clear about the difference of dynamic and static linking.
If I use a library with static linking,
is that mean I copy the code i need from library for my program and link with them?
Then my program can work with the code from library.
If i use a library with dynamic linking,
is that mean I only reference the code i need from library to my program when my program is running.
Then my program can work with the "reference code".
#import vs. #include and static vs. dynamic linking are two completely unrelated topics.
#include includes the contents of a file directly in another file, and is available in C (and therefore also in Objective-C). However, it's common to want to include the contents of a file only if that file hasn't already been included. (You don't, for example, want to declare the same variables twice; it'd cause compiler errors!) That's why #import was added in Objective-C; it does exactly that: includes the contents of a file only if that file hasn't already been #imported. If you're not sure what to use, you should probably be using #import.
Static vs. dynamic linking is completely different--linking happens after compilation, so it couldn't possibly be related to #import and #include, which are part of the source code. Your thoughts on linking are exactly correct, however--statically linked libraries are included in your app, and your users don't need them. Dynamically linked libraries are referenced, and must be present on your users' machines for your app to run.