Xcode #ifdef DEBUG is not working properly - objective-c

I have add following line to the code.
#ifdef DEBUG
//DEBUG only code
#endif
And I have go to the project->info tab in the xcode and set 'command-line builds use' to debug and run the code the code snippet inside the 'if' executed. The problem is when i set the command-line build' use to release and run the code. The code snippet inside the if condition still runs. I have set the preprocessor DEBUG macros to 'DEBUG=1'without quotes. How to solve this.

The #ifdef syntax means "is defined", without regard to value; in other words, it is defined if it has any value at all (0 or 1).
You probably want the #if syntax instead. This requires that the value actually be set to 1.

Related

Turn on autocomplete/hints for code between preprocessor lines

I have some code wrapped between the following statements:
#if POTATO
(a few lines of c code)
#endif
Unfortunately, autocompletion, highlighting, suggestions and everything else stops working for any code between the #if statements. How can I fix this?

How can a CMake variable be hidden?

I have a CMake project which lets a globally set variable (set with -DARDUINO_SDK_PATH=/a/b/c on command line) disappear i.e. suddenly the given value is gone which leads to a fatal error.
I know there are different ways to "hide" a variable (e.g. inside functions or external projects)
In my case:
the variable is not being set explicitly anywhere in the code (e.g. via set() or find_path())
the access which leads to the error is on top level (i.e. not inside a function)
there are instructions (i.e. same file/line) where in one case the variable has the value it's been given and the next time it's gone
Tracing the variable with variable_watch(ARDUINO_SDK_PATH) I can see that everything works fine before the compiler is being checked:
cmake -DARDUINO_SDK_PATH=/a/b/c <path>
...
... everything fine, ${DARDUINO_SDK_PATH} == '/a/b/c' everywhere
...
-- Check for working C compiler: /usr/bin/avr-gcc
...
... here the variable is empty and not being traced any more
...
Here is my suggestion:
Does the compiler check (indicated by check for working C compiler .. on the terminal) have it's own variable space and does not know variables provided on command line?
Note: This question is a generalization of this question, which has become way too specialized but might offer some useful background information.
That any modification to variable is not traced after the variable_watch() command seems like a bug somewhere in CMake to me.
Generally speaking a "cached CMake variable" can be hidden by a "normal CMake variable" with the same name. But e.g. find_path() won't run again or modify a variable if already set.
Here is an example:
cmake_minimum_required(VERSION 2.4)
project(VariableWatchTest NONE)
variable_watch(MY_TEST_VAR)
set(MY_TEST_VAR "something" CACHE INTERNAL "")
message("${MY_TEST_VAR}")
set(MY_TEST_VAR "hiding something")
message("${MY_TEST_VAR}")
unset(MY_TEST_VAR)
message("${MY_TEST_VAR}")
find_path(MY_TEST_VAR NAMES "CMakeLists.txt" HINTS "${CMAKE_CURRENT_LIST_DIR}")
message("${MY_TEST_VAR}")
Would give (without the variable_watch() messages:
-- something
-- hiding something
-- something
-- something
References
What's the CMake syntax to set and use variables?
I'm not sure whether this is a bug or a feature but (at least some) CMake variables are not available in certain steps of the CMake configuration procedure.
You can check this by adding something like this to your toolchain file:
MESSAGE("FOO: ${FOO}")
and run CMake like this
cd build-dir
cmake -DFOO=TEST ..
You will likely see FOO printed with value TEST once in the beginning of the configuration process and later printed again but being empty.
Just don't access variables from the global space inside a toolchain file (doesn't belong there anyway).

How can I use cmake to test processes that are expected to fail with an exception? (e.g., failures due to clang's address sanitizer)

I've got some tests that test that clang's address sanitizer catch particular errors. (I want to ensure my understanding of the types of error it can catch is correct, and that future versions continue to catch the type of errors I'm expecting them to.) This means I have several tests that fail by crapping out with an OTHER_FAULT, which appears to be the fixed way that clang's runtime reports an error.
I've set the WILL_FAIL flag to TRUE for these tests, but this only seems to check the return value from a successful, exception-free failure. If the process terminates with an exception, cmake still classes it as a failure.
I've also tried using PASS_REGULAR_EXPRESSION to watch for the distinguishing messages that are printed out when this error occurs, but again, cmake seems to class the test as a failure if it terminates with an exception.
Is there anything I can do to get around this?
(clang-specific answers are also an option! - but I doubt this will be the last time I need to test something like this, so I'd prefer to know how to do it with cmake generally, if it's possible)
CTest provides only basic, commonly used interpretators for result of test programs. For implement other interpretators you can write simple program/script, which wraps the test and interpret its result as needed. E.g. C program (for Linux):
test_that_crash.c:
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
int main(int argc, char** argv)
{
pid_t pid = fork();
if(pid == -1)
{
// fork fails
return 1;
}
else if(pid)
{
// Parent - wait child and interpret its result
int status = 0;
wait(&status);
if(WIFSIGNALED(status)) return 0; // Signal-terminated means success
else return 1;
}
else
{
// Child - execute wrapped command
execvp(argv[1], argv + 1);
exit(1);
}
}
This program can be used in CMake as follows:
CMakeLists.txt:
# Compile our wrapper
add_executable(test_that_crash test_that_crash.c)
# Similar to add_test(name command), but test is assumed successfull only if it is crashed(signalled)
macro(add_test_crashed name command)
# Use generic flow of add_test() command for automatically recognize our executable target
add_test(NAME ${name} COMMAND test_that_crash ${command} ${ARGN})
endmacro(add_test_crashed)
# ...
# Add some test, which should crash
add_test_crashed(clang.crash.1 <clang-executable> <clang-args>)
There is also a clang-specific solution: configure its manner of exit using the ASAN_OPTIONS environment variable. (See https://github.com/google/sanitizers/wiki/AddressSanitizerFlags.) To do this, set the ASAN_OPTIONS environment variable to abort_on_error=0. When the address sanitizer detects a problem, the process will then do _exit(1) rather than (presumably) abort(), and will thus appear to have terminated cleanly. You can then pick this up using cmake's WILL_FAIL mechanism. (It's still not clear why OS X and Linux differ in this respect - but there you go.)
As a bonus, the test fails much more quickly.
(Another handy option that can improve turnaround time when running through cmake is to set ASAN_SYMBOLIZER_PATH to an empty value, which stops the address sanitizer symbolizing the stack traces. Symbolizing takes a moment, but there's no point doing it when running through cmake, since you can't see the output.)
Rather than do this by hand, I made a Python script that sets the environment appropriately on OS X (doing nothing on Linux), and invokes the test. I then add each asan test using a macro, along the lines of Tsyvarev's answer.
macro(add_asan_test basename)
add_executable(${basename} ${basename}.c)
add_test(NAME test/${basename} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/wrap_clang_sanitizer_test.py -a $<TARGET_FILE:${basename}>)
set_tests_properties(test/${basename} PROPERTIES WILL_FAIL TRUE)
endmacro()
This gives a simple pass/fail as quickly as possible. I'm in the habit of investigating failures by running the test in question from the shell by hand and examining the output, in which case I get the stack trace as normal (and the fact exiting by abort is a bit slow is less of a problem).
(There are similar options for the other sanitizers, but I haven't investigated them.)

Is #if preprocessor macro "running" #ifdef behind the scenes in Objective-C?

If I create a preprocessor macro named DEBUG for the Debug configuration of a project's target with the value 1, and not for the Release configuration, I find that using
#if DEBUG
...
#endif
compiles for Release builds too.
Firstly, is it checking if DEBUG is defined and after that if it evaluates to true? If yes, is it ok (or recommended) to use it this way instead of
#ifdef DEBUG
#if DEBUG
...
#endif
#endif
?
It's not recommended to use #if VARIABLE without checking that VARIABLE has been defined.
When #if evaluates the expression, it does the following:
It expands all macros in the expression (which means that an symbol which has not been #defined will be unchanged.)
It parses the result as an integer arithmetic expression, replacing any identifier with the integer 0.
So if DEBUG has not been #defined as a macro,
#if DEBUG
will be the same as
#if 0
which will also have the same effect as #ifdef DEBUG.
If you define DEBUG on the command-line with -DDEBUG, then there is an implicit
#define DEBUG 1
before the file is preprocessed, with the result that
#if DEBUG
is the same as
#if 1
which is also the same as #ifdef DEBUG.
However. If you did the following:
#define DEBUG
#if DEBUG
// ... stuff
#endif
the the #if will expand to:
#if
and you'll get an error message:
file.m:2:6: error: #if with no expression
As a result, it is unwise to use #if VARIABLE, unless you know for sure that VARIABLE has been defined as an integer.
Modern Xcode already provides a definition for DEBUG when building in debug mode.
The difference between #ifdef DEBUG and #if DEBUG is that #ifdef DEBUG will be true when the symbol is defined, no matter what value has been defined.
Thus, #define DEBUG=0 will be true for #ifdef DEBUG because it has a defined value (it will also be true for #define DEBUG for the same reason).
However, #if DEBUG will only be true if DEBUG has been defined with a non-zero value.

preserve whitespace in preprocessor macro value taken from environment variable

In an Objective-C project I am attempting to take a file path from an environment variable and set it as a location to write generated files. This is used to run test code using xcodebuild in an automated testing environment where the file path is not determined until xcodebuild is called.
In attempt to do this I am entering a preprocessor macro in the Build Settings that references the variable:
BUILDSERVER_WORKSPACE=\#\"$(WORKSPACE)\"
and then setting the value of a string using that macro
NSString *workspaceLocation = BUILDSERVER_WORKSPACE;
in cases where the (string value of) the path for $WORKSPACE does not contain spaces it works fine but in cases where the path has spaces, the macro preprocessor sees the whitespaces as a macro separator and attempts to process them as separate macro definitions.
for example:
$WORKSPACE=/foo/bar/thudblat
will set the value of workspacelocation as #"/foo/bar/thudblat"
but
$WORKSPACE="/foo/bar/thud blat"
ends up creating multiple preprocessor definitions:
#define BUILDSERVER_WORKSPACE #"/foo/bar/thud
#define blat"
I have attempted to stringify the path, but since the presence or absence of whitespace only happens when i call xcodebuild to build and then run and so I cannot get that to work.
In the end, what I want is to simply take the path at $WORKSPACE and set its value to the NSString *workspaceLocation
so that workspaceLocation could potentially be "\foo\bar\thud blat"
I thought I had tried every scheme of quoting and escaping but, the one thing I had not tried was quoting the entire thing as suggested by #nielsbot
BUILDSERVER_WORKSPACE="\#\"$(WORKSPACE)\""
with an unescaped quote at the beginning and end of the entire value statement. Thad did the trick and gave me the string: #"/foo/bar/thud blat" when calling xcodebuild.
You can achieve that with double stringize trick:
#define STRINGIZE_NX(A) #A
#define STRINGIZE(A) STRINGIZE_NX(A)
static NSString *kWorkspace = #( STRINGIZE(BUILDSERVER_WORKSPACE) );
The way it works is very well explained in here: https://stackoverflow.com/a/2751891/351305
If you wish to really read the environment variable at runtime then you can simply obtain it from NSProcessInfo:
NSString *workspaceLocation = NSProcessInfo.processInfo.environment[#"WORKSPACE"];
That will give you the current value of the environment variables, spaces and all.
HTH