Preprocessor Macros in Xcode with Swift - xcode

I'm having trouble replicating in Swift the Preprocessor Macro functionality offered by ObjC. I have heard that Swift has no preprocessor, so I'm looking for another way to implement this.
My end goal is to build my project using the command line tools, passing in a custom variable and value, which will be preprocessed and inserted into the code at specific points, before the build takes place.
This is the solution for ObjC:
Use this command to run a test:
xcodebuild \
test \
-scheme TestUserDefinedVariablesObjC \
-destination 'platform=iOS Simulator,name=iPhone 6' \
MY_VAR=42
I use MY_VAR in code like this:
int a = MY_VAR;
(I add MY_VAR to Preprocessor Macros in my target's Build Settings like this: MY_VAR=$(MY_VAR))
As a last resort, I could add pre-action to the scheme's Run phase that substitutes the correct values using sed or something like that, but it's not a great solution.

Are you using different keyset/keyboard? If so check "
example:
Preprocessor Macros in my target's Build Settings
MY_VAR=\"42\"
check " character. Change it with this "

Instead of using SED in a build-phase script, you could use the clang preprocessor.
For example, put this in a file named macro-test.c
#if DEBUG
#define LOG(A) print(A)
#else
#define LOG(A)
#endif
import Foundation
func hello()
{
LOG("Hello, Swift macro!")
let theAnswer = MY_CONST
print("The answer = ", theAnswer)
}
Add a script build phase that runs the clang preprocessor:
#!/bin/sh
if [ $CONFIGURATION == "Debug" ] ;
then
DEBUG="1"
else
DEBUG="0"
fi
MY_CONST=42
clang -E -P -DMY_CONST=$MY_CONST -DOS=$OS -DDEBUG=$DEBUG "${SOURCE_ROOT}/macro-test.c" > "${SOURCE_ROOT}/macro-test.swift"
Add the generated swift file to the Xcode project.

Related

Swift 4 Conditional compile logic not working correctly

Here's some simple code to show the problem I am having:
import UIKit
let TEST = true
print(TEST)
#if TEST
print("1. TEST should be true. Value is : ", TEST)
#endif
#if !TEST
print("2. TEST should be false. Value is : ", TEST)
#endif
Regardless of whether TEST is 'true' or 'false', the '#if !TEST' is always executed. The '#if TEST' branch is never executed.
This happens in a Playground and in compiled code.
Xcode 9 Beta 5
You are confusing between TEST the local variable and TEST the compiler flag.
What you have is a local variable named TEST
What you are testing for is the existence of a compiler flag named TEST
To set a compiler flag, go to the target's Build Settings and search for Other Swift Flags, then add -DTEST to your Debug build.
Also, Swift compiler flags are much simpler compared to C compiler flags: a flag either exists or not. You can't associate an int value or anything like that. Consequently, there's no point in getting its value. It's a true/false situation: you know that it exists or not; there's no other value associated with it.

How to pass macro definition which generating from ShellScripts to source code in Android.mk

Using Android NDK,I want to get git version in my c++ source code.
so i implement my function like this:
const char *GetGitVersion()
{
#ifdef GIT_VERSION
return GIT_VERSION;
#else
return NULL;
#endif
}
in Android.mk:
LOCAL_CPPFLAGS += -D'GIT_VERSION="$(shell $(LOCAL_PATH)/get_version.sh)"'
in get_version.sh:
GIT_VERSION=`git --no-pager log --abbrev=7 -n 1 --pretty=format:"%h %ci" HEAD | \
awk '{gsub("-", "");print $2"-"$1}'`
echo Git-$GIT_VERSION
My problem is :
When i first build my program,it works.But when i have submited my changes and the git version has changed, the Compiler has not build my source code. Function GetGitVersion return previous version. Why? is there any other method to implement my requirement?
Sorry,my English is poor!
you need to recompile your lib so the function implementation can be updated.
However, if there are no changes in the source file where GetGitVersion() is defined, it may not be recompiled.
To force a recompilation of your sourcefile, you can use touch source.c (linux/unix) or copy /b source.c +,, (windows) to update your file last modification time.

How to test the static_assert in my library with cmake?

in my library code I have a bunch of static_asserts. I want to test if they fire under the expected conditions.
I would like to write a range of test files and
ensure that they fail to compile
check the output of the compilation attempt for the expected message from the static assert
Does anyone know how to do that with cmake?
AFAICT, try_compile is not the answer, because it is executed while running cmake. I need these checks to be executed during make.
You could set up a "nested" project for these tests, configure it as part of your CMake run and then build it using cmake --build; something like this:
Your normal CMakeLists.txt:
# ...
execute_process(
COMMAND ${CMAKE_COMMAND} path/to/test/project
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/TestProject
)
add_test(
NAME StaticAsserts
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/TestProject
COMMAND ${CMAKE_COMMAND} --build .
)
# ...
Of course, the test command could actually be a wrapper script running cmake --build internally and processing its output.
As an alternative, you could move the configuration of the nested project into the test as well, perhaps using CTest to drive the configure & build.
After several more experiments, this is what I am doing now:
add_executable(
fail_test
EXCLUDE_FROM_ALL
fail_test.cpp
)
add_custom_command(OUTPUT fail_test.out
COMMAND ${CMAKE_MAKE_PROGRAM} fail_test > ${CMAKE_CURRENT_BINARY_DIR}/fail_test.out 2>&1 || true
COMMAND grep "int i = row.alpha" ${CMAKE_CURRENT_BINARY_DIR}/fail_test.out > /dev/null
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/fail_test.cpp
COMMENT "fail_test"
)
add_custom_target(test_constraints DEPENDS fail_test.out COMMAND true)
This is what it does:
Create a target for compiling the code that is supposed to fail at compile time. Exclude this target from the default build so that it does not create a mess.
Add a custom command that calls make for this fail-target, pipes the compiler spew into a file, ignores the result code and then greps for the expected compiler message that indicates that the compilation failed due to the expected reason.
Make the custom command depend on the source file, so that the compilation is tested again when the source file is ended.
Add the custom command as dependency to a custom target.
Of course, for more tests, steps 1, 2 and 4 would go into a function.
So now I can call
make test_constraints
to test if the stuff I want to fail compiling actually does so. And if something does not fail as expected, I can even call
make fail_test
to tune the test or its basis until it fails correctly.
For platform independence, the custom command will probably have to be adjusted. Suggestions welcome.
Add this to your CMakeLists.txt:
include(CTest)
# Test that code is NOT able to compile
function(TestStaticCheck TEST_NAME)
add_executable(${TEST_NAME} EXCLUDE_FROM_ALL ${TEST_NAME}.cpp)
target_link_libraries(${TEST_NAME} MyLibrary)
add_test(NAME ${TEST_NAME}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${TEST_NAME}
)
set_tests_properties(${TEST_NAME} PROPERTIES WILL_FAIL TRUE)
endfunction()
TestStaticCheck(TestFoo)
Then put this in TestFoo.cpp in the same directory as your CMakeLists.txt:
int main()
{
// Code that should NOT compile
}

Escaping quotes for COMPILE_DEFINITIONS

Currently I'm working on a cmake script to compile generated C code. I'm trying to generate a Visual Studio 10 project. The code contains several #include statements which have to be preprocessed before compilition:
#indude INC_FILE
Before starting with CMake the code was compiled with a manually maintained Visual Studio project. I added a preprocessor definition to replace INC_FILE with the final include header:
INC_FILE="foo.h"
For my new CMak script I tried to add this statement to the COMPILE_DEFINITION variable:
set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY COMPILE_DEFINITION "INC_FILE="foo.h"")
Sadly this doesn't work because the quotes are removed. In the generated visual studio project I found the in the project file:
INC_FILE=foo.h
I tried to escape the quotes:
"INC_FILE=\"foo.h\""
INC_FILE=\"foo.h\"
"INC_FILE=\\"foo.h\\"
"INC_FILE="foo.h"
All the above mentions possibilites didn't work. Are there any other tricks in cmake to get a correct quotes escaping for my preprocessor definition?
Tested with cmake 2.8.12.1:
add_executable(foo foo.cpp)
target_compile_definitions(foo PUBLIC FOO_INCL="foo.hpp")
Note 1
You can use include option instead of file's name macro:
#if defined(FOO_INCLUDE_SOME_FILE)
# include "some_file.hpp"
#elif defined(FOO_INCLUDE_OTHER_FILE)
# include "other_file.hpp"
#endif
IMHO it looks much cleaner.
Note 2
If you have a bad time with special characters use configure_file command:
> cat some_file.hpp.in
#include "#FOO_INCLUDE_FILE#"
> cat CMakeLists.txt
set(FOO_INCLUDE_FILE "other_file.hpp")
configure_file(some_file.hpp.in ${foo_BINARY_DIR}/include/some_file.hpp #ONLY)

Extract build flags from XCode from the command line

I'm using X-Code 4.2 and wish to use the VIM editor and clang-complete vim script to do code completion. It works fine if I manually set up the clang-complete configuration to reflect the settings in my X-Code project. To make this work more smoothly I'd like to do the following.
get_compile_options some_src.m
where some_src.m is a valid source file in my XCode project. The output from get_compile_options should be all the build flags that XCode would use to build this into an object file. Any ideas on how to accomplish this.
AFAIK there is no fair method to accomplish this, but you may add special target into Xcode project, disable dsym generation, resources copying, add user-defined option 'CC=<your custom compiler>' where '<your custom compiler>' will be your script which records parameters passed into it. 'some_src.m' will be right after '-c' option. This way you will collect options for each file by compiling your special target.
I have successfully used this approach with patched version of clang.
I think that I found better solution, you can use xctool.
You can pass path to your xcode project, scheme (target), and get json with compile commands.
$1 = path to .xcodeproj file
$2 = scheme (target)
$3 = path for generated json
#!/bin/bash
XCTOOL_DIR=/Documents/xctool-master #the location of your xctool
$XCTOOL_DIR/xctool.sh -workspace "$1"/project.xcworkspace \
-scheme "$2" \
-reporter json-compilation-database:"$3"/compile_commands.json build
compile_commands.json is json compilation database
it has format:
[
{ "directory": "/home/user/llvm/build",
"command": "/usr/bin/clang++ -Irelative -DSOMEDEF=\"With spaces, quotes and \\-es.\" -c -o file.o file.cc",
"file": "file.cc" },
...
]
and you can parse it with usual json parsers,
also you can use other reporters

Resources