1

I am developing in XCode on Mac OS X El Capitan 10.11.4. My project mixes C, C++11 and Embedded Python.

My project works as I can invoke a Python script and return the data to C++ by embedding python. In my project I use absolute paths as pythons search path to load the script from 'C'.

XCode project/
-- Python.framework/
-- python/
---- mypython.py
-- python_interface.c
-- main.cpp

My questions are:

Q1: I have brew Python available but this isn't seen from XCode, instead the system supplied one is. This isn't a problem for now but I would eventually like to know how to point to my chosen installation.

I have bundled the brew Python.framework into my project so it links successfully. I know it doesn't invoke this because if I specify my module path incorrectly it complains the system python can not find it. Also, 'system(which python)' reports '/usr/bin/python'.

Q2: How do I specify relative search paths to python within XCode, i.e. to locate my local python module from 'C' code within my project?

Q3: How do I determine the absolute path of python 'requests' installation at runtime? My python module imports this and it could be different than what I specify.

Currently, I use Py_GetPath and Py_SetPath to indicate these using absolute paths, i.e. '/usr/local/lib/python2.7/site-packages' for 'requests'.

I know how to locate the module path within python itself (Find path of module without importing in Python) but this is not what I want to do. I need to know the path before my script is run.

As mentioned I am embedding python, so I am making the call from 'C' to my python script (see https://docs.python.org/2/extending/embedding.html?highlight=embedded#pure-embedding).

I have found the following links that show how to get the path of the executable. What I would like is the path of the project and use relative paths from that to locate my python module.

Relative Paths Not Working in Xcode C++

Programmatically retrieving the absolute path of an OS X command-line app

I have found this posting; Relative imports for the billionth time. My search path from 'C' code to my python script is relative but I believe this post is mainly about python scripts importing other modules relative to each other.

Q4: The result of adding or linking Frameworks to an XCode project is the same. In my case the Python.framework appears in the 'Project navigator' and it is added to the 'Link Binaries With Libraries' section. Yet the following two articles indicate that there is a difference between the two. It is not the size of the executable as I have tried both methods and this remains the same.

https://developer.apple.com/library/ios/recipes/xcode_help-structure_navigator/articles/Adding_a_Framework.html

This states;

"The frameworks you add this way are third-party-built bundles containing the framework’s object code and runtime resources. See related articles for information about linking to a framework without adding it to the project."

and contains a link to "Linking to a Library or Framework", whose url seems to contradict this (AddingaLibrarytoaTarget).

https://developer.apple.com/library/ios/recipes/xcode_help-project_editor/Articles/AddingaLibrarytoaTarget.html#//apple_ref/doc/uid/TP40010155-CH17

Thanks.

Community
  • 1
  • 1
Dodomac
  • 194
  • 2
  • 17

1 Answers1

1

Some answers to my questions

I reorganised my project and created my own Makefile using various sources on google. This was because I wanted to port my project as I couldn't answer the above questions. I had worked with Makefiles some years before but I am relatively new to XCode.

To create my Makefile these are the resources I used;

The next step is to automate the process of generating Makefiles;


New Makefile project structure

project/
-- Debug/ or Release/ 
-- Makefile
-- obj/
---- target .o files
-- python/
---- .py files
-- src/
---- C/C++ files incl headers

Makefile

# https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html#Automatic-Variables
# $@ Contains the target file name.
# $< Contains the first dependency file name.
# $^ The names of all the prerequisites, with spaces between them.

# Produces a Release build by default, or Debug build with ‘make debug’

EXEC = $(BUILD_DIR)/my_exe_name

CCFLAGS=-c -Wall
CXXFLAGS=-c -Wall -std=c++11
BINARY_DIR=Obj
BUILD_DIR=Release

PYTHON_CCFLAGS=$(shell python2.7-config --cflags)
PYTHON_LDFLAGS=$(shell python2.7-config --ldflags)

CPP_FILES := $(wildcard src/*.cpp)
C_FILES := $(wildcard src/*.c)

CPP_OBJ_FILES := $(addprefix $(BINARY_DIR)/,$(notdir $(CPP_FILES:.cpp=.o)))
C_OBJ_FILES := $(addprefix $(BINARY_DIR)/,$(notdir $(C_FILES:.c=.o)))

C_HEADERS = $(filter-out $(addsuffix .h, $(basename $(SOURCE_FILES))), $(wildcard src/*.h))
CPP_HEADERS = $(filter-out $(addsuffix .h, $(basename $(SOURCE_FILES))), $(wildcard src/*.hpp))

### Take the BUILD_DIR as a dependency but ignore it’s timestamp
### as it will change whenever something is written into it

$(EXEC): $(C_OBJ_FILES) $(CPP_OBJ_FILES) | ${BUILD_DIR}
    @echo [ $(EXEC) ]
    $(CXX) $(LD_FLAGS) $(PYTHON_LDFLAGS) -o $(EXEC) $^

### The objects in the BINARY_DIR folder require the BINARY_DIR to be created
### as well as any changes to the other dependencies

$(BINARY_DIR)/%.o: src/%.cpp $(CPP_HEADERS) $(C_HEADERS) | ${BINARY_DIR}
    @echo [ make $@ ]
    $(CXX) $(CXXFLAGS) $(C11_FLAGS) -o $@ $<

$(BINARY_DIR)/%.o: src/%.c $(C_HEADERS) | ${BINARY_DIR}
    @echo [ make $@ ]
    $(CC) $(CCFLAGS) $(PYTHON_CCFLAGS) -o $@ $<

${BINARY_DIR}:
    mkdir $(BINARY_DIR)

$(BUILD_DIR):
    mkdir $(BUILD_DIR)

### clean the targets. We can have either Debug or Release but I don’t know
### how to specify either in one line, i.e. we don’t want to do ‘make clean debug’
### to specify the Debug folder

.PHONY: clean cleanmsg cleanrel cleandeb

clean: cleanmsg cleanrel cleandeb
    rm -r -f $(BINARY_DIR)

cleanmsg:
    @echo Cleaning product and all .o files

cleanrel:
    rm -r -f Release

cleandeb:
    rm -r -f Debug

# Debug build
# Ensure these are last. I had them below the original decl of the flags
# and they were always set! Now you have to ‘make debug’ for it to take effect

.PHONY: debug
debug: CCFLAGS += -DDEBUG -g
debug: CXXFLAGS += -DDEBUG -g
debug: BUILD_DIR=Debug
debug: $(EXEC)

Using XCode with new Makefile project

To continue using XCode to develop my project I created an XCode project over my Makefile project. See http://hiltmon.com/blog/2015/08/01/simple-c-plus-plus-from-makefiles-to-xcode-builds/


Answers

By doing this I am able to somewhat answer the above questions. Q3 is still unanswered.

A1: Create a Makefile project and within it state the platform specified python installation. This way you do not need to bundle it into your XCode project.

See https://docs.python.org/2/extending/embedding.html?highlight=embedded#compiling-and-linking-under-unix-like-systems.

A2: Make the XCode project relative so your product resides in your project. Not the best answer if you want your exe installed in /usr/local/bin.

See How to change output directory for a target (gp_coder's answer).

My Makefile stores the exe in either ./Release/ (make), or ./Debug/ (make debug). So does XCode but with different leading directories that are several levels deep. To change this, simply specify the current dir '.' in XCode for the Targets "Project Settings>Advanced>Custom>Products" destination directory, this will then match the Makefile.

My python search path is set to

:../python:/usr/local/lib/python2.7/site-packages

'../' because my exe is in ./Debug or./Release and python/ is relative to that.

However, if you were to invoke the exe from the cmdline one dir up it wouldn't work. e.g. ./Release/my_exe_name. This is because it is taking the current dir and using the search path in relation to that.

It would be better to store and set the absolute path. See Where to store application data (non-user specific) on Linux

I posted a question on this before I realised the answer; How to set relative project path in XCode when target is /usr/local/bin

The second path is for my python requests directory. Q3 refers to this.

A3: Don't know. Still have to work out how to pass my installed python module path into my C code at runtime BEFORE invoking python, as this makes up my python search path. This value changes based on your installation.

A4: This wasn't really a question but a confusion. Specify this in your Makefile to avoid bundling.

Community
  • 1
  • 1
Dodomac
  • 194
  • 2
  • 17