How do I save files to $(PROJECT_DIR) from objective-c code? - xcode

I have code which generates resources which I want to save in a subdirectory of my $(PROJECT_DIR).
How do I get the real path from this environment variable in code?

open the projects build settings and add SAVEPATH=#\"$(PROJECT_DIR)\" to the preprocessor macros.
Then you can get the project directory like this:
NSString *projectDir = SAVEPATH;

I'm not sure if Xcode 3.2.6 has changed the way that () are used with environment variables, but I've found that using the following pre-processor macro works for me (#fluchtpunkt's answer gives me a compiler error):
PROJECT_DIR=#\""$PROJECT_DIR"\"
Then I can do:
NSString *savePath = [PROJECT_DIR stringByAppendingPathComponent:#"Save Folder"];

Related

How do you create custom build rules in QTCreator for code generation?

I'm working on a GTK3 application, but using QTCreator as my IDE, just because I happen to like it. It works fine, I can easily turn off all the QT-specific stuff and link the GTK libraries. There's just one little issue.
GTK uses XML files to define its resources. It comes with a program, "glib-compile-resources", which takes a .gresource.xml file and produces a .c file*, which can then be included in your project. The problem is that QTCreator doesn't know about glib-compile-resources, so I have to remember to run the program manually every time I make any change to them.
I've tried using a custom build step, but if I do that, then QT rebuilds the file every time, even if it hasn't changed, which slows the process down. In addition, if the C file doesn't already exist, it will fail with a "No rule to make target 'x.c' needed by 'x.o'. Stop." error, so I have to run the program manually anyway.
Is there any way to tell QTCreator to run glib-compile-resources whenever it encounters a .gresource.xml file, and include the resulting C file into the final compilation?
*There are other options available then just a straight C source file, but C source is the simplest and easiest for me.
You can add a custom target in your qmake file (rather than in your QtCreator project config). See the qmake docs at https://doc.qt.io/qt-5/qmake-advanced-usage.html#adding-custom-targets and/or https://doc.qt.io/qt-5/qmake-advanced-usage.html#adding-compilers.
Update: this is a simple example which shows how to do this for a single file, using the custom target mechanism in your .pro file:
glib_resources.target = glib-resources.c
glib_resources.depends = glib-resources.xml
glib_resources.commands = glib-compile-resources --target $$glib_resources.target --generate-source $$glib_resources.depends
QMAKE_EXTRA_TARGETS += glib_resources
PRE_TARGETDEPS += glib-resources.c ## set this target as a dependency for the actual build
QMAKE_CLEAN += glib-resources.c ## delete the file at make clean
Here's how I wound up solving my own issue:
I found in the QT documentation how to add your own custom compiler to a QT project file. The exact lines needed are:
GLIB_RESOURCE_FILES += \
resources.gresource.xml
# Add more resource files here.
glib_resources.name = glibresources
glib_resources.input = GLIB_RESOURCE_FILES
glib_resources.output = ${QMAKE_FILE_IN_BASE}.c
glib_resources.depend_command = glib-compile-resources --generate-dependencies ${QMAKE_FILE_IN}
glib_resources.commands = glib-compile-resources --target ${QMAKE_FILE_OUT} --sourcedir ${QMAKE_FILE_IN_PATH} --generate-source ${QMAKE_FILE_IN}
glib_resources.variable_out = SOURCES
glib_resources.clean = ${QMAKE_FILE_OUT}
QMAKE_EXTRA_COMPILERS += glib_resources
(Thanks to #zgyarmati, who's post lead me to the right answer.)

Qt Installer project: how to generate package.xml and config.xml

I try to make my Qt Installer project more comfortable.
I need to centralize information about my application and components (config.xml and package.xml) in one file. I don't want to jump on different files with same name and search for changeable elements between xml tags.
My first thougt is doing it right in *.pro file of installer project. I place sections of variables in header of installer project file. But where I need to place the code for xml generating?
What is the better (native / comfortable / crossplatform) way to do this?
The answer is simple here: you cannot generate XML files for Qt Installer: you write them manually, as explained in the documentation.
This section describes the following tasks that you must accomplish to create the installer:
Create a package directory that will contain all the configuration files and installable packages.
Create a configuration file that contains information about how to build the installer binaries and online repositories.
Create a package information file that contains information about the installable components.
Create installer content and copy it to the package directory.
Use the binarycreator tool to create the installer.
However, if you look closer at the examples, you can still generate the installer in the *.pro file. Let's pick an example randomly, System Info:
TEMPLATE = aux
INSTALLER = installer
INPUT = $$PWD/config/config.xml $$PWD/packages
example.input = INPUT
example.output = $$INSTALLER
example.commands = ../../bin/binarycreator -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT}
example.CONFIG += target_predeps no_link combine
QMAKE_EXTRA_COMPILERS += example
OTHER_FILES = README
If you want to apply this to your project, I think you'll have to modify the ../../bin/binarycreator line and make it system aware, by changing your PATH. It might be possible to call an external script and parse XML files, and make the substitutions you would like to do, but you'd move the complexity to another place.
Instead of maintaining plain good old XML files, you would be creating something between XSLT and XML. Maybe you could just write XSLT (or XSL or XQUERY) and generate XML but I don't know anyone who is using it anymore. Last time I used it was when I was learning Computer Science a long time ago :)
This is possible using the QMAKE_SUBSTITUTES feature which will substitute qmake variables into the given input files and put the output in the build folder.
This runs at qmake time rather than at build time. If this is suitable then you just need to add a target to copy the generated files from the build dir to your source dir.
If you need it to run at build time then you can create a .pri file containing QMAKE_SUBSTITUTES and a target in the main .pro file that will run qmake on this file during the build process.
Main .pro file:
create_xml.commands += $(QMAKE) $$shell_quote($$PWD/config/generate_xml.pri) $$escape_expand(\n\t)
create_xml.commands += $(COPY) $$shell_quote($${OUT_PWD}/config.xml) $$shell_quote($$PWD/config) $$escape_expand(\n\t)
create_xml.commands += $(COPY) $$shell_quote($${OUT_PWD}/package.xml) $$shell_quote($$PWD/packages/my.app.id/meta) $$escape_expand(\n\t)
create_xml.depends = $$PWD/version.pri
QMAKE_EXTRA_TARGETS += create_xml
generate_xml.pri:
TEMPLATE = aux
message("Generating $$OUT_PWD/config.xml and $$OUT_PWD/package.xml")
# Get the version number
include(version.pri)
APP_VERSION = $$VERSION
QMAKE_SUBSTITUTES += package.xml.in config.xml.in
config.xml.in: Note that you need to escape the quotes.
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<Installer>
<Name>MyApp</Name>
<Version>$$APP_VERSION</Version>
...

Xcode/GCC predefined macro for target name?

I was wondering if there is an Xcode or GCC preprocessor symbol for the target name of the application.
For example if I'm building an application called "MonkeyChicken", is there a preprocessor symbol such that
printf( __TARGET_NAME__ )
outputs:
MonkeyChicken
I don't believe there is any built-in (gcc has no idea what you're building when you compile a file), but you can always create one using GCC_PREPROCESSOR_DEFINITIONS in an xcconfig file (you are using xcconfig, right?) Something like this should work as you indicate above:
GCC_PREPROCESSOR_DEFINITIONS = __TARGET_NAME__=\"$(PRODUCT_NAME)\"

Project (bin) folder path at compile time?

Is there a way to find out the project path at compile time?
I want to create a unit test that tests if the configurartion in the default web.config (the one in the project folder). Mainly to reduce human error.
I cannot rely on assembly locations at runtime (for the test), so I need to know where the project folder is to access web.config there.
I need a "generic" solution since I'd like to use the same (base) test code for multiple projects, and the physical location is different anyway for most development machines.
Thanks.
Based on rkb's answer,
As it sounds like you've got a C# project, use this post build step.
echo namespace ProjectPath { static public class ProjectPath { public static readonly string Path = #"$(ProjectDir)";} } > $(ProjectDir)path.cs
Then include path.cs as an existing item to your test project. Then you can access it via:
string path = ProjectPath.ProjectPath.Path;
If you want the Visual Studio project path, at compile time, you could use a Pre-Build Event (see the Project Properties dialog) to run a command line that will create a source file used in your project.
The source file will contain some code, say a variable definition. Your testing code uses this variable. The value of the variable will come from VS; when it runs your Pre-Build Event command, it substitutes project properties for certain macros. The macro you want is probably ProjectDir.
So in the end, you have something like this for your Pre-Build Event's command:
echo 'const char * PROJECT_PATH = "$(ProjectDir)";' > source.cpp
Not sure what language you're using, so adjust accordingly.
To improve the solution slightly, instead of using the Post Build Event Command Line, you can run the command as an MSbuild Exec Task in the BeforeBuild Target of the project.

Can clang be told not to analyze certain files?

I'm trying to use clang to profile a project I'm working on. The project includes a rather large static library that is included in Xcode as a dependency.
I would really like clang to not analyze the dependencies' files, as it seems to make clang fail. Is this possible? I've been reading the clang documentation, and I haven't found it.
As a last resort, there is a brute force option.
Add this to the beginning of a file:
// Omit from static analysis.
#ifndef __clang_analyzer__
Add this to the end:
#endif // not __clang_analyzer__
and clang --analyze won't see the contents of the file.
reference: Controlling Static Analyzer Diagnostics
So, this isn't really an answer, but it worked well enough.
What I ended up doing was building the static library ahead of time, and then building the project using scan-build. Since there was already an up-to-date build of the static library, it wasn't rebuilt and thus wasn't scanned.
I'd still love to have a real answer for this, though.
Finally, in 2018 the option was implemented.
Use --exclude <path> [1] [2] option
--exclude
Do not run static analyzer against files found in this directory
(You can specify this option multiple times). Could be useful when
project contains 3rd party libraries.
I don't use XCode, but using scan-build in linux the following works for me. I my case, I want to run the static analysis on all first party, non-generated code. However, I want to avoid running it on third_party code and generated code.
On the command line, clang-analyzer is hooked into the build when scan-build sets CC and CXX environment variables to ccc-analyzer and c++-analyzer locations. I wrote two simple scripts called ccc-analyzer.py and c++-analyzer.py and hooked them in to the compile in place of the default. In these wrapper scripts, I simply looked at the path of the file being compiled and then run either the raw compiler directly (if I wish to avoid static analysis) or the c*-analyzer (if I wish for static analysis to occur). My script is in python and tied to my specific build system, but as an example that needs modification:
import subprocess
import sys
def main(argv):
is_third_party_code = False
for i in range(len(argv)):
arg = argv[i]
if arg == '-c':
file_to_compile = argv[i + 1]
if '/third_party/' in file_to_compile or \
file_to_compile.startswith('gen/'):
is_third_party_code = True
break
if is_third_party_code:
argv[0] = '/samegoal/bin/clang++'
else:
argv[0] = '/samegoal/scan-build/c++-analyzer'
return subprocess.call(argv)
if __name__ == '__main__':
sys.exit(main(sys.argv))
For Xcode users, you can exclude individual files from static analyzer by adding the following flags in the Target -> Build Phases -> Compile Sources section: -Xanalyzer -analyzer-disable-all-checks

Resources