So I am writing Automated tests that run from the command line to test the UI of my iOS application. I have the bash script working that cleans and builds the project and runs my UI Automated tests.
The problem is, I want the command-line script to be able to change a C Flag in my Xcode project that determines which server I am pointed at for my application. For example:
./run-test -target "Debug-Server"
will change the value of the C-Flag SERVER_ADDRESS to DEBUG_SERVER while:
./run-test -target "QA-Server"
changes the value of the C-Flag SERVER_ADDRESS to QA_SERVER
In order to do this, I plan to create a .xcconfig file that is fed into xcodebuild that will set the C Flags in my code to point to the correct server. Something like this:
xcodebuild -target <TARGET_NAME> -configuration Debug-QA.xcconfig -sdk "$DEVICE_SLUG""$CURRENT_SDK" DSTROOT=. clean build
I really am not familiar at all with .xcconfig files so I have a few questions about them.
Do I have to describe every build setting in my .xcconfig file? Or is there some kind of "default" value that Xcode uses?
Is there a better way of doing this?
I figured it out, used a combination of .xcconfig and #ifdef statements:
In the configuration file where I declare the server:
#ifdef USE_DEV
#define SERVER_ADDRESS DEV_SERVER_ADDRESS //USED IN AUTOMATED TESTING DEBUG SERVERS
#elif defined USE_QA
#define SERVER_ADDRESS QA_ADDRESSS //USED IN AUTOMATED TESTING STAGING SERVERS
#elif defined USE_LIVE
#define SERVER_ADDRESS LIVE_SERVER_ADDRESS //USED IN AUTOMATED TESTING LIVE SERVERS
#else
#define SERVER_ADDRESS DEV_SERVER_ADDRESS //DEFAULT VALUES
#endif
I then used three .xcconfig files which state the following:
dev.xcconfig:
GCC_PREPROCESSOR_DEFINITIONS = USE_DEV
QA.xcconfig:
GCC_PREPROCESSOR_DEFINITIONS = USE_QA
LIVE.xcconfig:
GCC_PREPROCESSOR_DEFINITIONS = USE_LIVE
Related
This has been on my mind for years. It is about using resource files with CMake in code such that they can be accessed when running in the build directory and when installed.
Say you have files necessary to run your program in a top-level directory called res. It contains res/file1.txt and res/file2.txt. You build this program and the resources are copied to the build directory from which the program can be run during development. Then, the program is installed with the resources into /usr/share/my_program or something and the program runs by accessing those files. The question is what to do in the source code so that the same code works when running from the build directory and when installed. I've seen several different answers for how to handle resources but each seems to have a flaw:
The program searches in some preconfigured absolute directory such as CMAKE_INSTALL_PREFIX/share/my_program and must be installed first to run, not ideal for easy use during development.
Finding some way to use relative paths to the binary but I don't see how this would work since the build tree will not mirror the installed file paths, being installed to the bin and share directories.
Differentiating between the two with a CMake variable so that it searches for a relative path in one scenario or the installed location with another. This could possibly just be the debug/release variable. It would also require rerunning CMake before installing to rebuild with the new resource paths.
Baking the files into the executable. Seems uneccessary when dealing with most resources since they could just be opened instead and may be inconvenient with large directories of files.
Is one of these the best solution? Is there something I'm not misunderstanding? I've always been under the impression programs should be able to be run from the build directory before installing to see if they work. If possible, I would like to know what both the CMake and C/C++ code would look like, such as open("my_resource_location"); and my_cmake_command(). Most answers I've seen relating to resources don't include both.
It seems to me that what you are looking for is a relocatable build.
One way to achieve this in CMake is to use configuration files to incorporate resource paths in your code. I have prepared a minimal and reproducible example to give you an idea of how it works.
First, imagine you have the following program structure on disk:
main
CMakeLists.txt
main.cpp
data
CMakeLists.txt
Resources.h.in (Thats the configuration file)
resource.txt
The resource.txt file only contains a string. The program simply opens that file, reads its content and displays it to the terminal. So you have something like:
#include <fstream>
#include <iostream>
#include <string>
#include <Resources.h>
const std::string MY_FILE = "/resource.txt";
int main(int argc, char *argv[])
{
std::string line;
std::ifstream myfile (RESOURCE_PATH + MY_FILE);
if(myfile.is_open())
{
while(std::getline(myfile,line))
{
std::cout << line << '\n';
}
myfile.close();
}
else
{
std::cout << "Unable to open file";
}
return 0;
}
Note that this file #includes a Resources.h file, but that this file does not exist in our project. However, we have a Resources.h.in configuration file that CMake will turn into a Resources.h file on generation. This generated file will then contain the resource path we need inside the RESOURCE_PATH variable. Here is what the configuration file contains:
#define RESSOURCE_PATH "#CMAKE_INSTALL_PREFIX#/#CMAKE_INSTALL_DATADIR#"
A simple #define with this strange #something# notation. On generation, CMake will make the appropriate substitution and write the result to Resource.h, which we can then consume. The main CMakeLists.txt file is pretty straight forward:
cmake_minimum_required(VERSION 3.10)
project(example)
# Sets up classic installation directories. However,
# you can override them:
include(GNUInstallDirs)
add_subdirectory(data)
add_subdirectory(main)
I use the GNUInstallDirs, which populates variables such as CMAKE_INSTALL_DATADIR, for convinience. The main/CMakeLists.txt file:
add_executable(example main.cpp)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Ressources.h.in" "Ressources.h")
target_include_directories(example
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
)
install(
TARGETS example
DESTINATION ${CMAKE_INSTALL_BINDIR}
)
This is where the configuration file is set up. The target_include_directories just below is added for CMake to be able to find the generated Resource.h file, which will reside in the build directory. Finally, the data/CMakeLists.txt file:
install(
FILES resource.txt
DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}
)
only has a simple installation instruction. From there, you can install as usual. Simply create a build directory and use CMake as usual. For example, if the build directory is located at the same level as the project:
mkdir ../build
cd ../build
cmake ../project
make
sudo make install
Since by default (on Linux) we have:
CMAKE_INSTALL_PREFIX=/usr/local
CMAKE_INSTALL_BINDIR=bin
CMAKE_INSTALL_DATADIR=share
The program will be installed to /usr/local/bin and the resource to /usr/local/share. Note that the Resource.h file will give you the correct path once generated by CMake. Whats is nice now, however, is that you can modify the value of CMAKE_INSTALL_PREFIX to point to somewhere else by calling CMake like so (for example, this could be a dev build directory):
cmake -DCMAKE_INSTALL_PREFIX=/home/someone/example ../project
and you will have these values instead:
CMAKE_INSTALL_PREFIX=/home/someone/example
CMAKE_INSTALL_BINDIR=bin
CMAKE_INSTALL_DATADIR=share
The Resources.h file will also be updated to point to the right location, and your resource will still be found.
I want some code to only be executed in a release build, but the code does not get executed when the scheme is configured to use the release configuration.
What am I missing?
I have the following in my app delegate's didFinishLaunchingWithOptions method:
#if RELEASE
Countly.sharedInstance().startOnCloudWithAppKey(appKey)
Crittercism.enableWithAppID(appID)
NSLog("crash logging enabled")
#endif
The target build settings look like this:
And the scheme is configured to use the Release configuration when I run the app:
You will need to set the preprocessor flags explicitly in the "Swift Compiler - Custom Flags" section, "Other Swift Flags" line.
Please check-
In absence of preprocessor macros, is there a way to define practical scheme specific flags at project level in Xcode project
It looks like the Swift compiler ignores -D flags that assign a specific value. If you use -DDEBUG and -DRELEASE, it seems to work.
now you need to set
Active Compilation Conditions
under Swift Compiler - Custom Flags
e.g.
Active Compilation Conditions DEV
you can check
#if DEV
print("DEV mode")
#else
print("PROD")
#endif
So I can write code like this:
#ifdef [whatever]
// do stuff that will never show up in the production version
#endif
Nothing useful per default, but you can set a DEBUG macro for debug builds in the "Preprocessor Macros" of the targets build settings and then do:
#ifdef DEBUG
// do stuff
#endif
If you want to automate that, edit the project templates in "/Developer/Library/Xcode/Project Templates":
Find the XCBuildConfiguration section(s) for which name = Debug;.
In the buildSettings add DEBUG to the list for GCC_PREPROCESSOR_DEFINITIONS if it exists
Otherwise add GCC_PREPROCESSOR_DEFINITIONS = (DEBUG); to the buildSettings
For per-user customizations and to avoid them being overwritten, see this question.
If you can assume that debug builds always use gcc -O0 (this is normally the case, but there may be odd exceptions where someone has changed the optimisation level for debug builds) then you can do this:
#if __OPTIMIZE__
// ... non-debug stuff ...
#else
// ... debug stuff ...
#endif
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.
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