I get different DLLs dependencies reported by different tools and like to deeply understand why. So answers like "tool xxx is crap, use cool yyy" are opinions and not welcome. Answers like "you have wrong path order" or "you missed to export XXX=yyyy" are not what I focus for, but if they are applicable, those are welcome too. What I exactly want to understand is for instance, which PE/ELF tables which of the tools use and which they can't see. All under the aspect of mingw / msys2 environment.
For completeness: I compiled my program inside Codelite IDE following exactly this Setup Instructions for Codelite and inserted /mingw64/bin:/clang64/bin: in front of PATH. The expectation is that this has nothing to do with my observation. Just for the case I couldn't see the wood because of all the trees. Inserted my code into the helloworld example.
For completeness II: the ucrt variant is installed for different projects. I did not use it here.
For completeness III: I give all my instructions here. Expecting, 80% have nothing to do with the question, but just in case you see things I missed.
Given: MSYS2 (Sept.2022, msys2-x86_64-20220904.exe) with:
pacman -Suy \
mingw-w64-x86_64-gcc \
base-devel development \
sys-utils \
mingw-w64-ucrt-x86_64-toolchain mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain \
libmodbus \
mingw-w64-x86_64-codelite
Opened a MSYS terminal:
$ which gcc && which g++ && which clang
/mingw64/bin/gcc
/mingw64/bin/g++
/mingw64/bin/clang
codelite &
Inside Codelite I only changed Settings | Build Settings | Compilers to "MinGW 32bit (MSYS2 64bit)" and therein the two cfg lines:
make C:/c/msys64/mingw32/bin/mingw32-make.exe -j8 SHELL=sh.exe
makedir mkdir -p
Program was then built via codelite generated makefile:
C:\WINDOWS\system32\cmd.exe /C C:/c/msys64/mingw32/bin/mingw32-make.exe -j8 SHELL=sh.exe -e -f Makefile
...[cut]...
C:/c/msys64/mingw32/bin/g++.exe -c protocol_writer.cpp" -g -O0 -Wall -o Debug/protocol_writer.cpp.o -I. -I.
C:/c/msys64/mingw32/bin/g++.exe -c scan_dtsu666_main.cpp" -g -O0 -Wall -o Debug/scan_dtsu666_main.cpp.o -I. -I.
C:/c/msys64/mingw32/bin/g++.exe -o Debug/modbus-dtu-dump #"modbus-dtu-dump.txt" -L. -lmodbus
====0 errors, 0 warnings====
Program was not starting because of missing DLLs (no pop-up or error msg). Now we come to the core issue. I invoked:
$ which ldd
/usr/bin/ldd
$ ldd modbus-dtu-dump.exe
ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffdf2c70000)
ntdll.dll => /c/Windows/SysWOW64/ntdll.dll (0x77310000)
wow64.dll => /c/WINDOWS/System32/wow64.dll (0x7ffdf2510000)
wow64win.dll => /c/WINDOWS/System32/wow64win.dll (0x7ffdf1be0000)
$ which objdump
/mingw64/bin/objdump
$ objdump --private-headers modbus-dtu-dump.exe | grep 'DLL'
DLL Name: libgcc_s_dw2-1.dll
DLL Name: KERNEL32.dll
DLL Name: libmodbus-5.dll
DLL Name: msvcrt.dll
DLL Name: libwinpthread-1.dll
DLL Name: libstdc++-6.dll
... and wonder, why ldd doesn't tell anything about the mingw runtimes, while objdump doesn't tell about the windows os core dependencies.
Edit:
As I wrote in a side note "Program was not starting because of missing DLLs (no pop-up or error msg).", there seems to be another miss-configuration. Once I changed the IDE settings to use the 64bit target, it was able to start and all-aspect debugging. I'll keep this up to date, for the case Google leads some people to here, searching for similar codelite or mingw problems. Goal is to have both architectures compile-able and debug-able.
On Debian 8 GNU/Linux, I'm trying to compile some Objective-C code from this tutorial using Clang and GNUstep make. I ran the following commands to install a build pipeline:
sudo apt-get install build-essential clang gnustep-devel
These are the files I am using:
GNUmakefile:
CC = clang
include $(GNUSTEP_MAKEFILES)/common.make
TOOL_NAME = Main
Main_OBJC_FILES = main.m Car.m
include $(GNUSTEP_MAKEFILES)/tool.make
main.m:
#import <Foundation/Foundation.h>
#import "Car.h"
int main () {
#autoreleasepool {
Car *toyota = [[Car alloc] init];
[toyota setModel:#"Toyota Corolla"];
NSLog(#"Created a %#", [toyota model]);
toyota.model = #"Toyota Camry";
NSLog(#"Changed the car to a %#", toyota.model);
[toyota drive];
}
return 0;
}
Car.h:
#import <Foundation/Foundation.h>
#interface Car : NSObject {}
#property (copy) NSString *model;
- (void)drive;
#end
Car.m:
#import "Car.h"
#implementation Car {
double _odometer;
}
#synthesize model = _model;
- (void)drive {
NSLog(#"Driving a %#. Vrooom!", self.model);
}
#end
I am compiling with:
. /usr/share/GNUstep/Makefiles/GNUstep.sh && make -k
When I compile, I get the following errors:
Car.m:4:10: error: inconsistent number of instance variables specified
double _odometer;
^
Car.m:7:13: error: synthesized property 'model' must either be named the same as a compatible instance variable or must
explicitly name an instance variable
#synthesize model = _model;
To fix the errors, I need to update the Car interface to:
#interface Car : NSObject {
NSString * _model;
double _odometer;
}
And the Car implementation to:
#implementation Car {
NSString * _model;
double _odometer;
}
It seems like my current compilation setup is forcing me to write more code than the tutorial suggests is needed in order to compile. In fact, in the tutorial, the author specifically recommends against including "protected instance variables" in the interface:
#interface Car : NSObject {
// Protected instance variables (not recommended)
}
I feel like I am using an outdated / misconfigured compilation setup. Am I? If so, how can I fix it so I can write code like in the referenced tutorial? (I'd prefer to use GNUstep make rather than the Clang CLI, if possible.)
From this answer I found that my problem might have been that I was not using a "modern" Objective-C runtime.
Instance variable declarations inside the #implementation { } block is
a relatively recent Objective-C feature. . . . you also need to be
eligible for the "Modern" Objective-C runtime . . .
From this thread I found,
Providing -fobjc-nonfragile-abi will also make some changes to the
runtime. On Darwin it will use Apple's 'Modern' runtime, while not
specifying it will generate code for the 'Legacy' runtime. If you
specify -fobjc-nonfragile-abi and -fgnu-runtime, then clang will
generate code for the GNUstep runtime, which you can find in GNUstep
svn as libobjc2. This provides all of the ObjC 2 features except for
GC, and a few others not found in the Mac runtimes.
So, I tried adding the following to my GNUmakefile:
Main_OBJCFLAGS = -fobjc-nonfragile-abi
But when I tried to compile, I got the error:
fatal error: 'objc/blocks_runtime.h' file not found
From there, I found this thread and concluded that I probably needed "libobjc2".
Disappointingly, I couldn't find a "libobjc2" package for Debian, so I attempted to compile it from source. First I had to install some build dependencies:
sudo apt-get install cmake llvm-dev
Then I had to apply this patch to the llvm-3.5-dev package, because it was causing the libobjc2 compilation to fail:
wget -qO- https://launchpadlibrarian.net/221945609/fix-llvm-3.5-dev-debian.bash | bash
So then I was able to compile libobjc2 with the following commands:
wget http://download.gna.org/gnustep/libobjc2-1.7.tar.bz2
tar jxf libobjc2-1.7.tar.bz2
cd libobjc2-1.7
mkdir Build
cd Build
CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_LIBDIR=lib ..
make -j8
sudo -E make install
After that, I tried to compile the code from the tutorial again. Compilation succeeded (without making any of the changes that I didn't want to make)! However, make complained about a "potential conflict" between one of my ".so" files (I can't recall the exact error), and when I ran my program (with ./obj/Main), I saw the following in the program output:
$ ./obj/Main
Loading two versions of Protocol. The class that will be used is undefined
Loading two versions of Object. The class that will be used is undefined
2016-11-19 16:43:24.012 Main[10166] Created a Toyota Corolla
2016-11-19 16:43:24.017 Main[10166] Changed the car to a Toyota Camry
2016-11-19 16:43:24.017 Main[10166] Driving a Toyota Camry. Vrooom!
Apparently, compiling libobjc2 and letting it live alongside the Debian GNUstep packages may not have been "good." So, I took the advice of various online sources and set out to compile GNUstep from source.
First I uninstalled the Debian packages:
sudo apt-get uninstall gnustep-devel && sudo apt-get autoremove
Then I installed the following build dependencies:
sudo apt-get install libffi-dev libicu-dev libgnutls28-dev libxml2-dev libxslt1-dev libtiff5-dev libjpeg-dev libpng-dev libgif-dev libaspell-dev libcups2-dev libaudiofile-dev portaudio19-dev libdispatch-dev
(I can't guarantee that's the complete list of dependencies, only the ones I could find documented; I may have had a few more necessary libraries already installed on my computer as a result compiling unrelated programs.)
Using the following two tutorials (1) (2), adapting them slightly (perhaps unnecessarily), I managed to compile GNUstep.
wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-make-2.6.8.tar.gz | tar xz
wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-base-1.24.9.tar.gz | tar xz
wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-gui-0.25.0.tar.gz | tar xz
wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-back-0.25.0.tar.gz | tar xz
cd gnustep-make-2.6.8
CC=clang ./configure --enable-objc-nonfragile-abi
sudo make install
cd ..
cd gnustep-base-1.24.9
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" ./configure
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" make
sudo make install
cd ..
cd gnustep-gui-0.25.0
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" ./configure
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" make
sudo make install
cd ..
cd gnustep-back-0.25.0
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" ./configure
CC=clang OBJCFLAGS="-fblocks -fobjc-nonfragile-abi" make
sudo make install
cd ..
After that, I compiled my tutorial files again, this time with:
. /usr/local/share/GNUstep/Makefiles/GNUstep.sh && make -k
At last, I no longer get an error about any "conflict", and when I run the program, I no longer see the errors of the form "Loading two versions of . . ."
$ ./obj/Main
2016-11-19 19:56:07.450 Main[10822:10822] Created a Toyota Corolla
2016-11-19 19:56:07.451 Main[10822:10822] Changed the car to a Toyota Camry
2016-11-19 19:56:07.451 Main[10822:10822] Driving a Toyota Camry. Vrooom!
Success!
I've also refactored this solution slightly, into a script. That might be a little "cleaner" and easier to use. I'll paste the latest version here "just in case:"
#!/usr/bin/env bash
# It seems that many modern Objective-C features aren't available without
# libobjc2, which doesn't seem to be available as a Debian package. Also,
# compiling and using it alongside the Debian GNUstep packages doesn't work too
# well (it seems like they may each provide their own definition of the Protocol
# and Object classes). Basically, to get a fully-functioning Objective-C
# compilation environment on Debian 8, run this script.
# Please ensure any Debian GNUstep packages are uninstalled before running this
# script.
# Slightly adapted from
# http://wiki.gnustep.org/index.php/GNUstep_under_Ubuntu_Linux for Debian 8.
# Also, uses the latest stable versions of source packages as of this writing
# (hopefully to improve reproducability of success; but feel free to upgrade
# them if you want).
# If this script is successful, you should be able to compile a "main.m" program
# by running "make" in a directory with a "GNUmakefile" with these contents:
#
# include $(GNUSTEP_MAKEFILES)/common.make
# TOOL_NAME = Main
# Main_OBJC_FILES = main.m
# include $(GNUSTEP_MAKEFILES)/tool.make
# Show prompt function
function showPrompt()
{
if [ "$PROMPT" = true ] ; then
echo -e "\n\n"
read -p "${GREEN}Press enter to continue...${NC}"
fi
}
# Set colors
GREEN=`tput setaf 2`
NC=`tput sgr0` # No Color
# Set to true to pause after each build to verify successful build and installation
PROMPT=true
# Install Requirements
sudo apt update
echo -e "\n\n${GREEN}Installing dependencies...${NC}"
sudo apt -y install clang ninja cmake libffi-dev libxml2-dev \
libgnutls28-dev libicu-dev libblocksruntime-dev libkqueue-dev libpthread-workqueue-dev autoconf libtool \
libjpeg-dev libtiff5-dev libffi-dev libcairo2-dev libx11-dev libxt-dev libxft-dev \
llvm-dev libdispatch-dev
# https://bugs.launchpad.net/ubuntu/+source/llvm/+bug/1387011/comments/17
wget -qO- https://launchpadlibrarian.net/221945609/fix-llvm-3.5-dev-debian.bash | bash
# Create build directory
mkdir GNUstep-build
cd GNUstep-build
# Set clang as compiler
export CC=clang
export CXX=clang++
# Checkout sources
echo -e "\n\n${GREEN}Downloading sources...${NC}"
mkdir -p libobjc2 && wget -qO- https://github.com/gnustep/libobjc2/archive/v1.8.1.tar.gz | tar xz -C libobjc2 --strip-components=1
mkdir -p make && wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-make-2.6.8.tar.gz | tar xz -C make --strip-components=1
mkdir -p base && wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-base-1.24.9.tar.gz | tar xz -C base --strip-components=1
mkdir -p gui && wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-gui-0.25.0.tar.gz | tar xz -C gui --strip-components=1
mkdir -p back && wget -qO- ftp://ftp.gnustep.org/pub/gnustep/core/gnustep-back-0.25.0.tar.gz | tar xz -C back --strip-components=1
showPrompt
# Build GNUstep make first time
echo -e "\n\n"
echo -e "${GREEN}Building GNUstep-make for the first time...${NC}"
cd make
./configure --enable-debug-by-default --with-layout=gnustep --enable-objc-nonfragile-abi --enable-objc-arc
make -j8
sudo -E make install
. /usr/GNUstep/System/Library/Makefiles/GNUstep.sh
echo ". /usr/GNUstep/System/Library/Makefiles/GNUstep.sh" >> ~/.bashrc
# showPrompt
# Build libobjc2
echo -e "\n\n"
echo -e "${GREEN}Building libobjc2...${NC}"
cd ../libobjc2
rm -Rf build
mkdir build && cd build
cmake ../ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang -DCMAKE_ASM_COMPILER=clang -DTESTS=OFF
cmake --build .
sudo -E make install
sudo ldconfig
export LDFLAGS=-ldispatch
showPrompt
OBJCFLAGS="-fblocks -fobjc-runtime=gnustep-1.8.1"
# Build GNUstep make second time
echo -e "\n\n"
echo -e "${GREEN}Building GNUstep-make for the second time...${NC}"
cd ../../make
./configure --enable-debug-by-default --with-layout=gnustep --enable-objc-nonfragile-abi --enable-objc-arc
make -j8
sudo -E make install
. /usr/GNUstep/System/Library/Makefiles/GNUstep.sh
showPrompt
# Build GNUstep base
echo -e "\n\n"
echo -e "${GREEN}Building GNUstep-base...${NC}"
cd ../base/
./configure
make -j8
sudo -E make install
showPrompt
# Build GNUstep GUI
echo -e "\n\n"
echo -e "${GREEN} Building GNUstep-gui...${NC}"
cd ../gui
./configure
make -j8
sudo -E make install
showPrompt
# Build GNUstep back
echo -e "\n\n"
echo -e "${GREEN}Building GNUstep-back...${NC}"
cd ../back
./configure
make -j8
sudo -E make install
showPrompt
. /usr/GNUstep/System/Library/Makefiles/GNUstep.sh
echo -e "\n\n"
echo -e "${GREEN}Install is done. Open a new terminal to start using.${NC}"
There is a mistake in the tutorial that you read (or at least, missing information) -- in order to use #synthesize model = _model;, you indeed need to define an instance variable named _model; when you do, the error goes away.
Let's take a step back, though. A long time ago, Objective-C didn't have #property syntax to define properties. This tutorial shows #property (copy) NSString *model;, but doesn't immediately get into what that means. (Read the linked "properties module" to see more from the author about this subject.)
Before #property syntax, you defined all of your instance variables manually:
// In MyClass.h
#interface MyClass : NSObject {
// Visible instance variables. Can be marked #public, #private, and #protected to prevent access.
}
...
#end
In order to allow users to access your instance variables, it was good practice to write setters and getters (e.g. -model and -setModel:), and to leave your instance variables inaccessible. This follows the OOP model of protecting access to your inner state and allowing access only through a presentable interface.
This could be quite a tedious process, and was a lot of boilerplate (especially with manual memory management, KVO compliance, etc.). #property syntax came along to help with that.
When you declare an #property, it defines an instance variable for you, as well as implicitly creating the getter and setter methods. You can specify the memory management model to use in these getters and setters (e.g. strong, weak, assign, copy, etc.), atomicity, and so on. If you have a property called model, #property will generate a _model instance variable, along with -model and -setModel: (unless you define only a getter).
It used to be, however, that #property did not create an instance variable for you, only the getter and setter. If you wanted an instance variable, you had to either create it yourself, or explicitly request that the compiler do it. This is where the #synthesize line comes in. #synthesize model = _model; tells the compiler that you have created a _model instance variable yourself, and that the model property should use _model as the storage. The leading underscore for the property was simply convention to help differentiate between the property itself (alias for a setter/getter) and the underlying storage.
In any case, those are details of the past. With a modern compiler, you will not need an #synthesize line, as the compiler will generate the instance variable for you. Either add the variable yourself and keep the #synthesize model = _model; line (not recommended), or leave that line out.
Note also that if you do declare your own instance variables, they do not need to be repeated between your #interface and #implementation -- pick a place and put them there. I recommend the #implementation, since they need not be visible, but that is up to you.
When I compile things with gitbash and gcc, is there someway to shorten what I need to type?
In order to compile my helloworld program, I have to type the following in:
gcc -o helloworld.exe helloworld.m -I C:/GNUstep/GNUstep/System/Library/Headers -L C:/GNUstep/GNUstep/System/Library/Libraries -std=c99 -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
Most people use Makefiles (or something related, e.g. CMake) in order to ease development. Makefiles are similar to bash scripts (the syntax is similar as well). After you created a Makefile you can run make and it does exactly what you specified.
If you want to know how to run Automake on Windows, read this: How to run a makefile in Windows?
I am using MinGW64 (Windows 7) without MSYS and I have the following problem:
I have one dll, written in C99, which has to have the .mexw64 suffix so it can be used by Matlab. I would like to be able to link this dll form another dll (mexw64) dynamically but gcc won't allow me to link directly. I cannot do static linking, because both dlls have many functions of the same name which can be hidden by not exporting their symbols when creating the shared library.
So far, I have tried:
To create a symbolic link (with correct suffix and preffix) using mklink. This works, but I was not able to run mklink from the makefile. Maybe it is due to the fact I am not using MSYS which could have ln -s (I havent checked).
To do the copy of the first dll and correcting the suffix and prefix. This worked better than I expected, because on runtime the second dll actually uses the original .mexw64 and not the dll copy. I guess it is just because the .mexw64 is found first, but why is that .mexw64 searched in the first place? How the system know it is actually a dll?
My question is, is this correct/safe enough? Are there any other options?
Thanks for comments.
You should build a proper implib, either as a linker output or from a .def.
Linker:
$ gcc -shared -o testimpl.mexw64 testimpl.c -Wl,--out-implib,libtestimpl.a
$ dlltool -I libtestimpl.a
testimpl.mexw64
Or create a .def file, specifying an explicit LIBRARY:
$ cat testimpl.def
LIBRARY testimpl.mexw64
EXPORTS
test #1
$ dlltool -d testimpl.def -l libtestimpl.a
$ dlltool -I libtestimpl.a
testimpl.mexw64
And finally, link stuff:
$ gcc -o test.exe test.c libtestimpl.a
# or
$ gcc -o test.exe test.c -L. -ltestimpl
$ grep testimpl.mexw64 test.exe
Binary file test.exe matches
I tried the approach in this question, but it seems the linux version of ar is not the same as the mac version since I failed to combine the object files again.
What I basically want to do is is merge another static library into my Xcode static library build product via a run-script build phase.
Unfortunately I can't compile the other library directly into my project because it has it's own build system (therefore I use the compiled libs).
I think it should be possible to merge the other library via ar into the Xcode generated library without decompiling the build product. How do I accomplish this?
you can use libtool to do it
libtool -static -o new.a old1.a old2.a
If you're dealing with multi-architecture static libraries, a bit of extra manipulation is required to thin each library, combine the thinned versions, and then fatten the result. Here's a handy script which you can edit to your satisfaction which does all that in one. The example takes three iOS libraries path/to/source/libs/libone.a, path/to/source/libs/libtwo.a, and path/to/source/libs/libthree.a and merges them into a single library libcombined.a.
#! /bin/bash
INPATH="path/to/source/libs"
LIBPREFIX="lib"
LIBS="one two three"
LIBEXT=".a"
OUT="combined"
ARCHS="armv7 armv7s arm64"
for arch in $ARCHS
do
for lib in $LIBS
do
lipo -extract $arch $INPATH/$LIBPREFIX$lib$LIBEXT -o $LIBPREFIX$lib-$arch$LIBEXT
done
INLIBS=`eval echo $LIBPREFIX\{${LIBS// /,}\}-$arch$LIBEXT`
libtool -static -o $LIBPREFIX$OUT-$arch$LIBEXT $INLIBS
rm $INLIBS
done
OUTLIBS=`eval echo $LIBPREFIX$OUT-\{${ARCHS// /,}\}$LIBEXT`
lipo -create $OUTLIBS -o $LIBPREFIX$OUT$LIBEXT
rm $OUTLIBS
You should just be able to link one to the other. So... just use ld to merge the images.
You should use ar -r to create an archive on MacOS:
ar -x libabc.a
ar -x libxyz.a
ar -r libaz.a *.o