Facing lipo error while creating a single fat file - iphone

I am trying to create a single .a file which will contain 3 different .a files so that I could share only one .a file. This is the command I am using
lipo -create -output ./libOutput.a ./libInput1.lib ./libInput2.lib ./libInput3.lib
but I am getting this lipo error:
./libInput1.lib and ./libInput2.lib
have the same architectures (i386) and
can't be in the same fat output file
Any idea how to get rid of this?

So this is the second time I have been here. The answer did not fix my problem. What I have found is that this is actually a bug in Xcode. What has happened both times is that I come and find this answer and that is not my problem and then I'm messing around for hours trying to figure out what's going on and the next thing I know Xcode crashes. Open up Xcode again and magic the problem is gone.
So I am adding my answer to help me remember this next time.

A workaround that worked for me (because I couldn't figure out what part of the building process was creating an additional architecture target to the compilation):just remove the architecture from one of the two .a libraries.
First, you can list the architecture with a simple file command:
$ file libwhatever.a
libwhatever.a: Mach-O universal binary with 4 architectures
libwhatever.a (for architecture armv7): current ar archive random library
libwhatever.a (for architecture armv7s): current ar archive random library
libwhatever.a (for architecture arm64): current ar archive random library
libwhatever.a (for architecture i386): current ar archive random library
$ file libfoo.a
libfoo.a: Mach-O universal binary with 2 architectures
libfoo.a (for architecture i386): current ar archive random library
libfoo.a (for architecture x86_64): current ar archive random library
Then, this workaround is just about removing the i386 arch from the first libwhatever.a (which was supposed to be just for arm* arch in my case anyway).
lipo -remove i386 libwhatever.a -output /tmp/libwhatever.a
mv /tmp/libwhatever.a libwhatever.a
and then you can create/merge your .a files without any warning.

I just had that same error message, and it was due to the fact that I had my architecture set to "other" and had typed in arm6. To fix the problem I simply changed my architecture setting to one of the default values, in my case I picked Standard (arm6 arm7). The Architectures setting can be found in your project build settings.

OK, I got it working. Here is my (entire) version of the run script
# Taken from Ray Wenderlich tutorial: http://www.raywenderlich.com/65964/create-a-framework-for-ios
set -e
# If we're already inside this script then die
if [ -n "$RW_MULTIPLATFORM_BUILD_IN_PROGRESS" ]; then
exit 0
fi
export RW_MULTIPLATFORM_BUILD_IN_PROGRESS=1
RW_FRAMEWORK_NAME=${PROJECT_NAME}
RW_INPUT_STATIC_LIB="lib${PROJECT_NAME}.a"
RW_FRAMEWORK_LOCATION="${BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.framework"
OUTPUT_LOCATION="${HOME}/Desktop"
if [ ! -w ${OUTPUT_LOCATION} ] ; then OUTPUT_LOCATION="${XCS_OUTPUT_DIR}" ; fi
if [ ! -w ${OUTPUT_LOCATION} ] ; then OUTPUT_LOCATION="/tmp" ; fi
if [ ! -w ${OUTPUT_LOCATION} ] ; then echo "Couldn't find anywhere to write! Dying."; exit 1 ; fi
function build_static_library {
# Will rebuild the static library as specified
# build_static_library sdk
xcrun xcodebuild -project "${PROJECT_FILE_PATH}" \
-target "${TARGET_NAME}" \
-configuration "${CONFIGURATION}" \
-sdk "${1}" \
ONLY_ACTIVE_ARCH=NO \
BUILD_DIR="${BUILD_DIR}" \
OBJROOT="${OBJROOT}" \
BUILD_ROOT="${BUILD_ROOT}" \
SYMROOT="${SYMROOT}" $ACTION
}
function make_fat_library {
# Will smash 2 static libs together
# make_fat_library in1 in2 out
xcrun lipo -create "${1}" "${2}" -output "${3}"
}
# 1 - Extract the platform (iphoneos/iphonesimulator) from the SDK name
if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]; then
RW_SDK_PLATFORM=${BASH_REMATCH[1]}
else
echo "Could not find platform name from SDK_NAME: $SDK_NAME"
exit 1
fi
echo "RW_SDK_PLATFORM is ${RW_SDK_PLATFORM}"
# 2 - Extract the version from the SDK
if [[ "$SDK_NAME" =~ ([0-9]+.*$) ]]; then
RW_SDK_VERSION=${BASH_REMATCH[1]}
else
echo "Could not find sdk version from SDK_NAME: $SDK_NAME"
exit 1
fi
echo "RW_SDK_VERSION is ${RW_SDK_VERSION}"
# 3 - Determine the other platform
if [ "$RW_SDK_PLATFORM" == "iphoneos" ]; then
RW_OTHER_PLATFORM=iphonesimulator
else
RW_OTHER_PLATFORM=iphoneos
fi
echo "RW_OTHER_PLATFORM is ${RW_OTHER_PLATFORM}"
# 4 - Find the build directory
if [[ "$BUILT_PRODUCTS_DIR" =~ (.*)$RW_SDK_PLATFORM$ ]]; then
RW_OTHER_BUILT_PRODUCTS_DIR="${BASH_REMATCH[1]}${RW_OTHER_PLATFORM}"
else
echo "Could not find other platform build directory."
exit 1
fi
echo "BUILT_PRODUCTS_DIR is ${BUILT_PRODUCTS_DIR}"
echo "RW_OTHER_BUILT_PRODUCTS_DIR is ${RW_OTHER_BUILT_PRODUCTS_DIR}"
# remove alias and copy, if it's archive
UNINSTALLED_PRODUCTS_DIRECTORY="${BUILT_PRODUCTS_DIR}/../../IntermediateBuildFilesPath/UninstalledProducts"
if [ -d "$UNINSTALLED_PRODUCTS_DIRECTORY" ]; then
echo "Looks like we're archiving, fixing aliases..."
rm "${BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}"
cp "${UNINSTALLED_PRODUCTS_DIRECTORY}/${RW_INPUT_STATIC_LIB}" "${BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}"
fi
# Build the other platform.
build_static_library "${RW_OTHER_PLATFORM}${RW_SDK_VERSION}"
if [ -d "$UNINSTALLED_PRODUCTS_DIRECTORY" ]; then
echo "Looks like we're archiving, fixing aliases..."
rm "${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}"
cp "${UNINSTALLED_PRODUCTS_DIRECTORY}/${RW_INPUT_STATIC_LIB}" "${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}"
fi
# If we're currently building for iphonesimulator, then need to rebuild
# to ensure that we get both i386 and x86_64
if [ "$RW_SDK_PLATFORM" == "iphonesimulator" ]; then
build_static_library "${SDK_NAME}"
fi
# Join the 2 static libs into 1 and push into the .framework
make_fat_library "${BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}" \
"${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_INPUT_STATIC_LIB}" \
"${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}"
# Ensure that the framework is present in both platform's build directories
cp -a "${RW_FRAMEWORK_LOCATION}/Versions/A/${RW_FRAMEWORK_NAME}" \
"${RW_OTHER_BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.framework/Versions/A/${RW_FRAMEWORK_NAME}"
# Copy the framework
ditto "${RW_FRAMEWORK_LOCATION}" "${OUTPUT_LOCATION}/${RW_FRAMEWORK_NAME}.framework"
# Copy the resources bundle
ditto "${BUILT_PRODUCTS_DIR}/${RW_FRAMEWORK_NAME}.bundle" \
"${OUTPUT_LOCATION}/${RW_FRAMEWORK_NAME}.bundle"
echo "DONE. ***** FINAL FRAMEWORK AND BUNDLE WERE COPIED HERE: ${OUTPUT_LOCATION} *****"

Go the target YourLibUniversal/Build Phases/Run script
Then look if the script mentions SIMULATOR_DIR_32 and SIMULATOR_DIR_64
If yes, remove theses references and just set one reference SIMULATOR_DIR
I had:
SIMULATOR_DIR_32=${SYMROOT}/${CONFIGURATION}-iphonesimulator-i386
SIMULATOR_DIR_64=${SYMROOT}/${CONFIGURATION}-iphonesimulator-x86_64
...
lipo -create "${DEVICE_DIR}/lib${LIB_NAME}.a" "${SIMULATOR_DIR_32}/lib${LIB_NAME}.a" "${SIMULATOR_DIR_64}/lib${LIB_NAME}.a" -output "${INSTALL_DIR}/lib${LIB_NAME}Universal.a"
I changed it to that:
SIMULATOR_DIR=${SYMROOT}/${CONFIGURATION}-iphonesimulator-x86_64
...
lipo -create "${DEVICE_DIR}/lib${LIB_NAME}.a" "${SIMULATOR_DIR}/lib${LIB_NAME}.a" -output "${INSTALL_DIR}/lib${LIB_NAME}Universal.a"

Related

How to make a Linux Makefile work on Windows?

(Disclaimer: I am not at all a computer science genius, far from that. I may use bad terminology and I appologize.)
I need to run some tests using the google test library and I was provided with a Makefile to handle the execution but it won't run on my Windows machine (I use Visual Studio). It was made for a Linux environment so I'm not sure what i would need to modify in order to run it. I have used MinGW to run Makefiles of my own making in the past.
Here's how the Makefile looks like:
CC=g++
CFLAGS=-c -Wall -ggdb -I.
LDFLAGS=
SOURCES=main.c singlelinklist.c
TESTS=single_test.cpp
#TODO: Need a more elegant way of specifying objects and tests
GTESTDIR=~/environment/googletest
OBJECTS=$(SOURCES:.cpp=.o)
FLAGS = -Iinclude
#all: $(SOURCES) $(EXECUTABLE)
# These next lines do a bit of magic found from http://stackoverflow.com/questions/2394609/makefile-header-dependencies
# Essentially it asks the compiler to read the .cpp files and generate the needed .h dependencies.
# This way if any .h file changes the correct .cpp files will be recompiled
depend: .depend
.depend: $(SOURCES)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^ >> ./.depend;
include .depend
# End .h file magic
#$(EXECUTABLE): $(OBJECTS)
# $(CC) $(LDFLAGS) $(OBJECTS) -o $#
#.cpp.o:
# $(CC) $(CFLAGS) $< -o $#
clean:
# rm -rf *o $(EXECUTABLE) test_executable
rm -f ./.depend
rm $(GTESTDIR)/libgtest.a
rm $(GTESTDIR)/gtest-all.o
# Google test section
$(GTESTDIR)/libgtest.a:
$(CC) -isystem $(GTESTDIR) -I $(GTESTDIR) -pthread -c $(GTESTDIR)/gtest/gtest-all.cc -o $(GTESTDIR)/gtest-all.o
ar -rv $(GTESTDIR)/libgtest.a $(GTESTDIR)/gtest-all.o
# This will also recompile if any source file is changed.
test_executable: $(GTESTDIR)/libgtest.a $(TESTS) depend
$(CC) -isystem $(GTESTDIR) -pthread -ggdb $(TESTS) $(GTESTDIR)/gtest/gtest_main.cc $(GTESTDIR)/libgtest.a -o test_executable
test: test_executable
./test_executable --gtest_print_time=0
And here's how my workspace is structured.
(Seems like I can't embed pictures).

How to automatically activate virtualenvs when cd'ing into a directory

I have a bunch of projects in my ~/Documents. I work almost exclusively in python, so these are basically all python projects. Each one, e.g. ~/Documents/foo has its own virtualenv, ~/Documents/foo/venv (they're always called venv). Whenever I switch between projects, which is ~10 times a day, I do
deactivate
cd ..
cd foo
source venv/bin/activate
I've reached the point where I'm sick of typing deactivate and source venv/bin/activate. I'm looking for a way to just cd ../foo and have the virtualenv operations handled for me.
I'm familiar with VirtualEnvWrapper which is a little heavy-handed in my opinion. It seems to move all your virtualenvs somewhere else, and adds a little more complexity than it removes, as far as I can tell. (Dissenting opinions welcome!)
I am not too familiar with shell scripting. If you can recommend a low-maintenance script to add to my ~/.zshrc that accomplishes this, that would be more than enough, but from some quick googling, I haven't found such a script.
I'm a zsh/oh-my-zsh user. oh-my-zsh doesn't seem to have a plugin for this. The best answer to this question would be someone contributing an oh-my-zsh plugin which does this. (Which I might do if the answers here are lackluster.
Add following in your .bashrc or .zshrc
function cd() {
builtin cd "$#"
if [[ -z "$VIRTUAL_ENV" ]] ; then
## If env folder is found then activate the vitualenv
if [[ -d ./.env ]] ; then
source ./.env/bin/activate
fi
else
## check the current folder belong to earlier VIRTUAL_ENV folder
# if yes then do nothing
# else deactivate
parentdir="$(dirname "$VIRTUAL_ENV")"
if [[ "$PWD"/ != "$parentdir"/* ]] ; then
deactivate
fi
fi
}
This code will not deactivate the virtualenv even if someone goes into subfolder. Inspired by answers of #agnul and #Gilles.
If the virtualenv is made by pipenv, then please consider this wiki page.
Furthermore, for added security please consider direnv.
Put something like this in your .zshrc
function cd() {
if [[ -d ./venv ]] ; then
deactivate
fi
builtin cd $1
if [[ -d ./venv ]] ; then
. ./venv/bin/activate
fi
}
Edit: As noted in comments cd-ing into a subfolder of the current virtual env would deactivate it. One idea could be to deactivate the current env only if cd-ing into a new one, like
function cd() {
builtin cd $1
if [[ -n "$VIRTUAL_ENV" && -d ./venv ]] ; then
deactivate
. ./venv/bin/activate
fi
}
that could still be improved, maybe turning it into a "prompt command" or attempting some prefix matching on the folder names to check there's a virtual env somewhere up the path, but my shell-fu is not good enough.
You should try something like autoenv if not direnv.
The first one is considered to be "lightweight", while the second one "simply, higher quality software", listening respectively to each one's author, talking about the other one's project. Thus, they seem to me fairly good options, to try both!
Anyway, both have been tested on zsh shells.
In particular, autoenv is really simple to use, after installing it:
$ git clone git://github.com/inishchith/autoenv.git ~/.autoenv
$ echo 'source ~/.autoenv/activate.sh' >> ~/.bashrc
just "follow the white rabbit " and try for example
$ mkdir project
$ echo "echo 'whoa'" > project/.env
$ cd project
whoa
"If a directory contains a .env file, it will automatically be executed when you cd into it. When enabled (set AUTOENV_ENABLE_LEAVE to a non-null string), if a directory contains a .env.leave file, it will automatically be executed when you leave it."
Have a look at https://github.com/inishchith/autoenv for more detailed instructions!...
Rather than writing a custom script you could use direnv. It's not a zsh specific solution (for that you could try zsh-autoenv), but is well-maintained and easy to use with zsh. Once you've installed it, you'd want to put eval "$(direnv hook zsh)" at the end of your .zshrc. At that point you can do:
$ source ~/.zshrc
$ cd foo
$ echo "layout python" > .envrc
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
$ direnv allow
direnv: loading .envrc
direnv: export +VIRTUAL_ENV ~PATH
Now you should be in your virtualenv. You can test by running pip freeze to see that your virtualenv specific packages are installed. To deactivate
$ cd ..
direnv: unloading
By far the easiest option (in 2019+) is to add virtualenvwrapper into your ~/.zshrc plugins
For example:
plugins=(
git pip python brew virtualenvwrapper
)
For anyone using (or considering to use) pyenv this can be achieved very conveniently using the pyenv-virtualenv plugin as described here.
Basically you simply add a .python-version file to the directory in which the name of the virtualenv is specified.
For posterity: I used #MS_'s solution but ran into the problem where cding directly from one project to another deactivates the old virtualenv but doesn't activate the new one. This is a slightly modified version of that solution which solves this problem:
# auto activate virtualenv
# Modified solution based on https://stackoverflow.com/questions/45216663/how-to-automatically-activate-virtualenvs-when-cding-into-a-directory/56309561#56309561
function cd() {
builtin cd "$#"
## Default path to virtualenv in your projects
DEFAULT_ENV_PATH="./env"
## If env folder is found then activate the vitualenv
function activate_venv() {
if [[ -f "${DEFAULT_ENV_PATH}/bin/activate" ]] ; then
source "${DEFAULT_ENV_PATH}/bin/activate"
echo "Activating ${VIRTUAL_ENV}"
fi
}
if [[ -z "$VIRTUAL_ENV" ]] ; then
activate_venv
else
## check the current folder belong to earlier VIRTUAL_ENV folder
# if yes then do nothing
# else deactivate then run a new env folder check
parentdir="$(dirname ${VIRTUAL_ENV})"
if [[ "$PWD"/ != "$parentdir"/* ]] ; then
echo "Deactivating ${VIRTUAL_ENV}"
deactivate
activate_venv
fi
fi
}
This is a zsh only solution.
This is an improvement over daveruinseverything's answer which is an improvement over MS_'s answer.
We are using precmd hook instead of overwriting cd.
We have added another extra feature. Suppose the directory structure is
├── .venv
│ ├── bin
│ │ └── activate
├── subdir
│ ├── subdir1
│ │ ├── subdir2
│ │ │ └── test2.txt
│ │ └── test1.txt
│ └── test.txt
└── testing.py
If you now open new terminal in subdir2, or directly cd to subdir2 from other place, it will activate the venv.
The solution is:
autoload -Uz add-zsh-hook
add-zsh-hook precmd automatically_activate_python_venv
function automatically_activate_python_env() {
if [[ -z $VIRTUAL_ENV ]] ; then
activate_venv
else
parentdir="$(dirname ${VIRTUAL_ENV})"
if [[ "$PWD"/ != "$parentdir"/* ]] ; then
deactivate
activate_venv
fi
fi
}
function activate_venv() {
local d n
d=$PWD
until false
do
if [[ -f $d/.venv/bin/activate ]] ; then
source $d/.venv/bin/activate
break
fi
d=${d%/*}
# d="$(dirname "$d")"
[[ $d = *\/* ]] || break
done
}
that is the solution without cd'ing, with zsh set to setop auto_cd w'll be able to change directories without cd, just type directory name and hit enter.
it is anhence of above solution:
# auto activate virtualenv
# Modified solution based on https://stackoverflow.com/questions/45216663/how-to-automatically-activate-virtualenvs-when-cding-into-a-directory/56309561#56309561
function auto_active_env() {
## Default path to virtualenv in your projects
DEFAULT_ENV_PATH="./env"
## If env folder is found then activate the vitualenv
function activate_venv() {
if [[ -f "${DEFAULT_ENV_PATH}/bin/activate" ]] ; then
source "${DEFAULT_ENV_PATH}/bin/activate"
echo "Activating ${VIRTUAL_ENV}"
fi
}
if [[ -z "$VIRTUAL_ENV" ]] ; then
activate_venv
else
## check the current folder belong to earlier VIRTUAL_ENV folder
# if yes then do nothing
# else deactivate then run a new env folder check
parentdir="$(dirname ${VIRTUAL_ENV})"
if [[ "$PWD"/ != "$parentdir"/* ]] ; then
echo "Deactivating ${VIRTUAL_ENV}"
deactivate
activate_venv
fi
fi
}
chpwd_functions=(${chpwd_functions[#]} "auto_active_env")
Similar to Jake's answer but supports cding from one virtualenv to another. In this case it deactivates the old virtualenv then activates the new one.
function cd() {
builtin cd "$#"
if [[ ! -z "$VIRTUAL_ENV" ]] ; then
# If the current directory is not contained
# within the venv parent directory -> deactivate the venv.
cur_dir=$(pwd -P)
venv_dir="$(dirname "$VIRTUAL_ENV")"
if [[ "$cur_dir"/ != "$venv_dir"/* ]] ; then
deactivate
fi
fi
if [[ -z "$VIRTUAL_ENV" ]] ; then
# If config file is found -> activate the vitual environment
venv_cfg_filepath=$(find . -maxdepth 2 -type f -name 'pyvenv.cfg' 2> /dev/null)
if [[ -z "$venv_cfg_filepath" ]]; then
return # no config file found
fi
venv_filepath=$(cut -d '/' -f -2 <<< ${venv_cfg_filepath})
if [[ -d "$venv_filepath" ]] ; then
source "${venv_filepath}"/bin/activate
fi
fi
}
Here is (yet) another solution to automatically activate a virtual environment; it's based on a number of the answers already posted here.
This will work for any Virtual Environment name or directory (not just ./env, ./venv, etc.). Also supports subdirectories, as well as cd-ing into symlinks of virtual environment (parent) folders.
This code searches for a pyvenv.cfg file instead of a particular named directory. If one is found within a subdirectory of the current folder, the environment is automatically activated. Once inside a virtual environment, that state is retained until you move out of the parent virtual environment directory, at which point the environment is deactivated.
Place this inside your .bashrc or .bash_profile.
function cd() {
builtin cd "$#"
if [[ -z "$VIRTUAL_ENV" ]] ; then
# If config file is found -> activate the vitual environment
venv_cfg_filepath=$(find . -maxdepth 2 -type f -name 'pyvenv.cfg' 2> /dev/null)
if [[ -z "$venv_cfg_filepath" ]]; then
return # no config file found
fi
venv_filepath=$(cut -d '/' -f -2 <<< ${venv_cfg_filepath})
if [[ -d "$venv_filepath" ]] ; then
source "${venv_filepath}"/bin/activate
fi
else
# If the current directory is not contained
# within the venv parent directory -> deactivate the venv.
cur_dir=$(pwd -P)
venv_dir="$(dirname "$VIRTUAL_ENV")"
if [[ "$cur_dir"/ != "$venv_dir"/* ]] ; then
deactivate
fi
fi
}
Personally I think it's an improvement on a lot of the solutions here, since it should work for any virtual environment
This is my solution, which:
checks if already at the currently active venv, and do nothing in that case
if there is a venv folder, deactivate the active one if there is one
activate the new venv whatever if there was an old one or not.
In my bash_aliases:
function cd() {
builtin cd "$#"
if [ $(dirname "$VIRTUAL_ENV") == $(pwd) ] ; then
# Already at the active virtual env
return
fi
if [[ -d ./venv ]] ; then
if type deactivate > /dev/null 2>&1 ; then
printf "Deactivating virtualenv %s\n" "$VIRTUAL_ENV"
deactivate
fi
source ./venv/bin/activate
printf "Setting up virtualenv %s\n" "$VIRTUAL_ENV"
fi
}
This is my solution:
If VIRTUAL_ENV is not set then:
Check if we're inside a virtual env
If yes, then activate it
Else (VIRTUAL_ENV is defined), check that the current folder starts with $VIRTUAL_ENV (removing the /venv part) and verify that the deactivate command exists
Deactivate teh environment
This is the script:
function cd() {
builtin cd $1
if [[ -z "${VIRTUAL_ENV}" ]]; then
if [[ -d ./venv && -f ./venv/bin/activate ]]; then
source ./venv/bin/activate
fi
elif [[ ! "$(pwd)" == ${VIRTUAL_ENV:0:n-5}* && ! -z "$(command -v deactivate)" ]]; then
deactivate
fi
}
Note: You need to add this to .bashrc. If it doesn't work, check if your .profile is not overriding your command (it happened to me)
Based on #MS_'s solution:
function cd() {
builtin cd "$#"
## If env folder is found then activate the vitualenv
if [[ -d ./venv ]] ; then
source ./venv/bin/activate
fi
if [[ -n "$VIRTUAL_ENV" ]] ; then
## check the current folder belong to earlier VIRTUAL_ENV folder
# if yes then do nothing
# else deactivate
parentdir="$(dirname "$VIRTUAL_ENV")"
if [[ "$PWD"/ != "$parentdir"/* ]] ; then
deactivate
fi
fi
}
I've used direnv in the past, as others have mentioned. Lyft use aactivator for this exact scenario.
Once the venv is built it must be activated (added to $PATH). We use aactivator to automatically activate the venv each time a user enters the service directory and deactivates as they leave.
I tried direnv as suggested by others but found it a bit too opinionated and it didn't exactly do what I wanted.
The solution below is for fish shell users only. Also, it assumes a pyproject.toml file and stdlib's venv, but that can be easily changed.
The fish shell has the concept of event handlers so you can easily define a function that gets run whenever an "event" gets triggered (Unix signals, environment variables changing, etc). See this a blog post for a quick introduction.
Add the following to your ~/.config/fish/config.fish (and modify as needed):
function venv_activate --on-variable PWD
if test ! -e pyproject.toml
if test -n "$VIRTUAL_ENV"
deactivate
end
return
end
# echo "Found pyproject.toml"
if test ! -d .venv
# echo "Creating $(python -V) venv"
python -m venv .venv --prompt (basename (pwd))
end
source .venv/bin/activate.fish
end
As a side note, the above works nicely with pyenv's .python-version files as well.
You don't have to execute deactivate on the directory where venv exists. When virtual environment is active you can deactivate anywhere.
So, say you have 2 venvs, <somepath>/project1/venv and <somepath>/project2/venv, and currently project1/venv is active.
If you want to switch project2/venv, do below.
cd project2
deactivate && source ./venv/bin/activate
It will deactivate previous one and activate current one.
Now the above you can just make an alias, or shell function in ~/.zshrc as below:
function avenv(){
deactivate
source ./venv/bin/activate
}
go the path where you want to activate the venv and just run avenv.
Python venv has a feature called --prompt, while creating venv you can mention the prompt, so that in the terminal you will understand which venv is active.
python3 -m venv venv --prompt PROJECT1_VENV
Now in terminal, it will come as (PROJECT1_VENV) -> ~
You can use a zsh hook function that runs whenever you change directories. For example, you could add this to your ~/.zshrc:
# Define a function to activate/deactivate virtualenvs based on the current directory
function venv_cd() {
# Check if the current directory has a venv subdirectory
if [[ -d venv ]]; then
# If yes, activate it if it's not already active
if [[ "$VIRTUAL_ENV" != "$PWD/venv" ]]; then
source venv/bin/activate
fi
else
# If no, deactivate the current virtualenv if any
if [[ -n "$VIRTUAL_ENV" ]]; then
deactivate
fi
fi
}
Add the function to the chpwd hook, which runs after every cd
add-zsh-hook chpwd venv_cd
Optionally, run the function once at the start of the session
venv_cd
This should automatically activate the virtualenv in the current directory if it exists, or deactivate it if you move to a directory without one.
Here is an alternative which sets an env variable when cd'ing into a virtualenv directory and checks if an active subdir is a child-directory of said virtualenv.
This will also deactivate when exiting or cd'ing to another directory.
This assumes you're using Pyenv to manage your Python installations, however you can change the pyvenv.cfg notation to anything else.
function cd() {
builtin cd "$#"
if [[ -f ./pyvenv.cfg ]] ; then
export VENV_CURRENT=$PWD
source ./bin/activate
else
if [[ $(env | fgrep VENV_CURRENT) ]]; then
if ! [[ $(pwd | fgrep $VENV_CURRENT) ]]; then
unset VENV_CURRENT
deactivate
fi
fi
fi
}

OpenSSL build script fails when run as a 'run script' phase within Xcode (succeeds outside of Xcode)

I'm attempting to run a script to build OpenSSL for iOS (armv6, armv7 and i386) as a 'run script' phase in Xcode.
The script builds successfully when run from the command line as a stand alone script. The result is a compiled libcrypto.a, libssl.a and include directory with the headers.
However, when I run the script as a run script phase in Xcode, it gets towards the end of make and errors out stating that it couldn't find any symbols referenced from libcrypto.
shlib_target=; if [ -n "" ]; then \
shlib_target="bsd-gcc-shared"; \
fi; \
LIBRARIES="-L.. -lssl -L.. -lcrypto" ; \
make -f ../Makefile.shared -e \
APPNAME=openssl OBJECTS="openssl.o verify.o asn1pars.o req.o dgst.o dh.o dhparam.o enc.o passwd.o gendh.o errstr.o ca.o pkcs7.o crl2p7.o crl.o rsa.o rsautl.o dsa.o dsaparam.o ec.o ecparam.o x509.o genrsa.o gendsa.o genpkey.o s_server.o s_client.o speed.o s_time.o apps.o s_cb.o s_socket.o app_rand.o version.o sess_id.o ciphers.o nseq.o pkcs12.o pkcs8.o pkey.o pkeyparam.o pkeyutl.o spkac.o smime.o cms.o rand.o engine.o ocsp.o prime.o ts.o" \
LIBDEPS=" $LIBRARIES " \
link_app.${shlib_target}
( :; LIBDEPS="${LIBDEPS:--L.. -lssl -L.. -lcrypto }"; LDCMD="${LDCMD:-/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc -arch i386}"; LDFLAGS="${LDFLAGS:--isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -DOPENSSL_THREADS -pthread -D_THREAD_SAFE -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DTERMIOS -O3 -fomit-frame-pointer -Wall}"; LIBPATH=`for x in $LIBDEPS; do echo $x; done | sed -e 's/^ *-L//;t' -e d | uniq`; LIBPATH=`echo $LIBPATH | sed -e 's/ /:/g'`; LD_LIBRARY_PATH=$LIBPATH:$LD_LIBRARY_PATH ${LDCMD} ${LDFLAGS} -o ${APPNAME:=openssl} openssl.o verify.o asn1pars.o req.o dgst.o dh.o dhparam.o enc.o passwd.o gendh.o errstr.o ca.o pkcs7.o crl2p7.o crl.o rsa.o rsautl.o dsa.o dsaparam.o ec.o ecparam.o x509.o genrsa.o gendsa.o genpkey.o s_server.o s_client.o speed.o s_time.o apps.o s_cb.o s_socket.o app_rand.o version.o sess_id.o ciphers.o nseq.o pkcs12.o pkcs8.o pkey.o pkeyparam.o pkeyutl.o spkac.o smime.o cms.o rand.o engine.o ocsp.o prime.o ts.o ${LIBDEPS} )
Undefined symbols for architecture i386:
"_ENGINE_load_gost", referenced from:
_ENGINE_load_builtin_engines in libcrypto.a(eng_all.o)
ld: symbol(s) not found for architecture i386
collect2: ld returned 1 exit status
make[2]: *** [link_app.] Error 1
make[1]: *** [openssl] Error 2
make: *** [build_apps] Error 1
I'm almost certain that this is a paths issue, but I can't figure out how to tell Xcode (or the script) which paths to use.
The script, available here, needed to be modified to account for the recent changes to the location of the developer tools with Xcode 4.3 (namely the fact that Developer/ is no longer at the root, but actually inside Xcode.app).
Here's the script for question completeness:
#!/bin/sh
# Automatic build script for libssl and libcrypto
# for iPhoneOS and iPhoneSimulator
#
# Created by Felix Schulze on 16.12.10.
# Copyright 2010 Felix Schulze. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
###########################################################################
# Change values here #
# #
VERSION="1.0.0c" #
SDKVERSION="5.0" #
# #
###########################################################################
# #
# Don't change anything under this line! #
# #
###########################################################################
CURRENTPATH=`pwd`
CURRENTPATH="${CURRENTPATH}/openssl"
set -e
if [ ! -e openssl-${VERSION}.tar.gz ]; then
echo "Downloading openssl-${VERSION}.tar.gz"
curl -O http://www.openssl.org/source/openssl-${VERSION}.tar.gz
else
echo "Using openssl-${VERSION}.tar.gz"
fi
mkdir -p "${CURRENTPATH}/src"
tar zxf openssl-${VERSION}.tar.gz -C "${CURRENTPATH}/src"
rm openssl-${VERSION}.tar.gz
cd "${CURRENTPATH}/src/openssl-${VERSION}"
############
# iPhone Simulator
echo "Building openssl for iPhoneSimulator ${SDKVERSION} i386"
echo "Please stand by..."
export CC="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc -arch i386"
mkdir -p "${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}.sdk"
LOG="${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}.sdk/build-openssl-${VERSION}.log"
./configure BSD-generic32 --openssldir="${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}.sdk" > "${LOG}" 2>&1
# add -isysroot to CC=
sed -ie "s!^CFLAG=!CFLAG=-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${SDKVERSION}.sdk !" "Makefile"
make >> "${LOG}" 2>&1
make install >> "${LOG}" 2>&1
make clean >> "${LOG}" 2>&1
#############
#############
# iPhoneOS armv6
echo "Building openssl for iPhoneOS ${SDKVERSION} armv6"
echo "Please stand by..."
export CC="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc -arch armv6"
mkdir -p "${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv6.sdk"
LOG="${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv6.sdk/build-openssl-${VERSION}.log"
./configure BSD-generic32 --openssldir="${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv6.sdk" > "${LOG}" 2>&1
sed -ie "s!^CFLAG=!CFLAG=-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${SDKVERSION}.sdk !" "Makefile"
# remove sig_atomic for iPhoneOS
sed -ie "s!static volatile sig_atomic_t intr_signal;!static volatile intr_signal;!" "crypto/ui/ui_openssl.c"
make >> "${LOG}" 2>&1
make install >> "${LOG}" 2>&1
make clean >> "${LOG}" 2>&1
#############
#############
# iPhoneOS armv7
echo "Building openssl for iPhoneOS ${SDKVERSION} armv7"
echo "Please stand by..."
export CC="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc -arch armv7"
mkdir -p "${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv7.sdk"
LOG="${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv7.sdk/build-openssl-${VERSION}.log"
./configure BSD-generic32 --openssldir="${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv7.sdk" >> "${LOG}" 2>&1
sed -ie "s!^CFLAG=!CFLAG=-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${SDKVERSION}.sdk !" "Makefile"
# remove sig_atomic for iPhoneOS
sed -ie "s!static volatile sig_atomic_t intr_signal;!static volatile intr_signal;!" "crypto/ui/ui_openssl.c"
make >> "${LOG}" 2>&1
make install >> "${LOG}" 2>&1
make clean >> "${LOG}" 2>&1
#############
echo "Build library..."
lipo -create ${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}.sdk/lib/libssl.a ${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv6.sdk/lib/libssl.a ${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv7.sdk/lib/libssl.a -output ${CURRENTPATH}/libssl.a
lipo -create ${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}.sdk/lib/libcrypto.a ${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv6.sdk/lib/libcrypto.a ${CURRENTPATH}/bin/iPhoneOS${SDKVERSION}-armv7.sdk/lib/libcrypto.a -output ${CURRENTPATH}/libcrypto.a
mkdir -p ${CURRENTPATH}/include
cp -R ${CURRENTPATH}/bin/iPhoneSimulator${SDKVERSION}.sdk/include/openssl ${CURRENTPATH}/include/
echo "Building done."
Even though this is an older post, I think the problem still persist. But I think I found a very simple solution. Just add the following line to the Build-Script, before "Configure" or "make" is called:
export COMMAND_MODE=unix2003
This should do the trick.
It's been logged as an issue on openssl.
Adjust your configure line:
./Configure darwin64-x86_64-cc zlib no-asm no-krb5 shared

SymbolicateCrash is not creating proper de-symbol file

I have the dSYM file for build created on client's machine. Client got a crash in build and now I am trying to de-symbol by use of the symbolicatecrash by the simple following command in terminal:
symbolicatecrash myapp_iPod-Touch.crash myapp.app.dSYM > test.txt
but it's not creating any meaningful de-symboled file. and it's giving the follwoing error in terminal:
Can't understand the output from otool
then I found a solution in following link:
iPhone SDK 3.0 and symbolicatecrash not getting along?
but still it's not de-symbolicating the exact memory location to exact code line responsible for crash.
Then I tried some other options too:
Following is the other option but didn't work:
symbolicatecrash.sh -A -v [crashlog-filename] MyApp.dSYM
For reference: http://apptech.next-munich.com/2010/01/symbolicatecrash.html
The best option that helped me is atos command to get the exact code line number of the crash but I want the systematic symbolicatecrash to create the dump.
NOTE: When I create build in my machine and desymbolicate (the my machine created) build's crash log in my machine it creates perfectly good dump file (show's exact memory location VS code line responsible for crash).
If you have the DSYM file for the crash then you can use this one:
#!/bin/bash
if [[ $# < 2 ]]
then
echo "Usage: $0 [-arch <arch> (defaults to whatever is specified in the crashlog- file] <dSYM-file> <crashlog-file>"
exit 1
fi
#Get the architecture either from the params or from the crashlog itself
ARCH_PARAMS=''
if [[ "${1}" == '-arch' ]]
then
ARCH_PARAMS="-arch ${2}"
shift 2
else
ARCHITECTURE=$(cat "${2}" | grep -A1 "Binary Images:" | grep 0x | sed -E -n 's/.*(armv[6-9]).*/\1/p')
if [ -n "${ARCHITECTURE}" ]
then
ARCH_PARAMS="-arch ${ARCHITECTURE}"
else
echo "Couldn't determine architecture based on the crashlog. Please specify it by calling $0 -arch <arch> <dSYM-file> <crashlog-file>"
exit
fi
fi
echo "Assuming architecture:" ${ARCHITECTURE}
#Store the other params
SYMBOL_FILE="${1}"
CRASHLOG="${2}"
#Get the identifier out of the crashlog
IDENTIFIER=$(cat "${CRASHLOG}" | egrep -o "^Identifier:[[:space:]]*.*$" | sed 's/^Identifier:[[:space:]]*\(.*\)$/\1/')
echo "Identifier:" $IDENTIFIER
echo
echo
#Iterate through the crashlog files, find the ones that belong to the $IDENTIFIER, sed the address out of those files, symbolicate them with atos and finally replace them back into those line again. Print all other lines untouched.
while read line
do
SYMBOL=$(echo $line | sed -E -n "s/.*(${IDENTIFIER}[[:space:]]*)(0x[[:alnum:]]*).*/\2/p" | atos -o "${SYMBOL_FILE}/Contents/Resources/DWARF/${IDENTIFIER}" ${ARCH_PARAMS})
if [ -n "$SYMBOL" ]
then
echo $line | sed -E "s/(${IDENTIFIER}[[:space:]]*)(0x[[:alnum:]]*)(.*)/\1\2 ${SYMBOL}/"
else
echo $line
fi
done < "${CRASHLOG}"

How to write a Makefile rule to download a file only if it is missing?

I'm trying to write a Makefile which should download some sources if and only if they are missing.
Something like:
hello: hello.c
gcc -o hello hello.c
hello.c:
wget -O hello.c http://example.org/hello.c
But of course this causes hello.c to be downloaded every time make command is run. I would like hello.c to be downloaded by this Makefile only if it is missing. Is this possible with GNU make and how to do this if it is?
My guess is that wget doesn't update the timestamp on hello.c, but retains the remote timestamp. This causes make to believe that hello.c is old and attempts to download it again. Try
hello.c:
wget ...
touch $#
EDIT: The -N option to wget will prevent wget from downloading anything unless the remote file is newer (but it'll still check the timestamp of the remote file, of course.)
Since the Makefile should be working as you want, you need to check a few unlikely cases:
1) Check that you don't have any .PHONY rules mentioning the source file.
2) Check that the source target name matches the file path you are downloading.
You could also try running make -d to see why make thinks it needs to 're-build' the source file.
The Makefile you wrote downloads hello.c only if it's missing. Perhaps you are doing something else wrong? See for example:
hello: hello.c
gcc -o hello hello.c
hello.c:
echo 'int main() {}' > hello.c
And:
% make
echo 'int main() {}' > hello.c
gcc -o hello hello.c
% rm hello
% make
gcc -o hello hello.c
% rm hello*
% make
echo 'int main() {}' > hello.c
gcc -o hello hello.c
(the echo command was not executed the second time)
If the prerequisite for hello.c has changed or is empty and Make continues to download the file when it exists, then one option to prevent Make from re-downloading the file is to use a flag in the body of the target to detect if the file exists:
hello.c:
test -f $# || wget -O hello.c http://example.org/hello.c
The test command will return true if the hello.c file exists, otherwise it will return false and the wget command will run.