Debugging C code that uses libtiff - c

I've written a lot of code over the years, but I haven't done much with C in the context of linux. Nor am I as familiar as I feel I should be with someone of the tools and utilities. Thanks in advance for your indulgence.
I'm trying to write some C code that uses libtiff. I need to be able to debug it line by line, including stepping through the libtiff source as appropriate. I'm using the Code::Blocks IDE and have that configured and working for basic "hello world" code, as well as a rudimentary calling of libtiff for proof-of-concept purposes. This is all working.
Here's my code:
#include "tiffio.h"
main()
{
TIFF* tif = TIFFOpen("test0.tiff", "r");
if (tif) {
uint32 imagelength;
tdata_t buf;
uint32 row;
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength);
buf = _TIFFmalloc(TIFFScanlineSize(tif));
for (row = 0; row < imagelength; row++)
TIFFReadScanline(tif, buf, row, 0);
_TIFFfree(buf);
TIFFClose(tif);
}
}
Stepping through my code above works fine. However, I can't step into any
of the libtiff function calls. I'm currently on ubuntu, using the default libtiff installed via apt-get. I'm assuming based on some reading I've done that the library isn't built with debugging symbols, which may be the source of my problem.
I'm assuming if that's indeed the problem, that I can compile a custom version of libtiff with the options I need, and have Code::Blocks compile/link against it instead of against the system default libraries. I've downloaded a fresh copy of libtiff, and am familiar with the make/make install process, but I'm not sure about the specifics of getting the compile set up properly for what I need. Some direction would be much appreciated.

Problem solved by uninstalling the system libtiff (not strictly necessary but was easiest for me to avoid any ambiguity on what version of libtiff I was using). Then configured Code::Blocks as follows (Project->Build Options):
Produce debubging symbols (-g) is checked
Enable common compiler warnings is checked
Other Compiler Options set to -fPIC
Linker Settings -> Other Linker Options set to -ltiff -L
Search Directories -> Compiler set to
Search Directories -> Linker set to
$LD_LIBRARY_PATH set to /home/depaan/amcdev/libtiff0/lib in Settings -> Environment -> Environment Variables (menu)
I'd previously complied libtiff locally as per the usual configure, make, make install... with
./configure --prefix=<desired_libtiff_location>
And CFLAGS set to "-g"
export CFLAGS="-g"

Related

GCC can't find headers on Windows

I'm new in winAPI and I was learning how code programs with some special functions and such, so I downloaded the Windows's SDK.
Problem is, GCC decided to put the blind glasses and say:
Documents_path.c:6:25: fatal error: KnownFolders.h: No such file or directory
#include<KnownFolders.h>
^
compilation terminated.
I said "OK, next one then" and there's another header with the same problem:
thread.c:3:30: fatal error: processthreadsapi.h: No such file or directory
#include<processthreadsapi.h>
^
compilation terminated.
I checked if these headers are even in my PC and here they are setting with windows.h, which it was working when I tried basic functions with it.
I searched an answer for this problem but didn't find any, either it was a external\binary libraries problem, is it local or not or a macro fix (which it didn't work).
How can I fix the problem?
EDIT:
I'm using VS Code
EDIT2:
This is the code of "Documents_path.c" example:
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<ShlObj.h>
#include<initguid.h>
#include<KnownFolders.h>
#pragma comment(lib, "user32.lib")
int main(){
int a;
PWSTR path = NULL;
HRESULT hr = SHGetKnownFolderPath(&FOLDERID_Documents, 0, NULL, &path);
if(SUCCEEDED(hr)){
printf("path for Documents is: %ls", path);
}
scanf("%d",&a);
CoTaskMemFree(path);
return 0;
}
And I'm reading the basics of winAPI from this website:
https://zetcode.com/gui/winapi/
as for structure of project folder:
C:\Users\ %USER%\Documents\C\dawd
MSVC uses Windows SDK while GCC does not.
On Windows GCC uses MinGW or MinGW-w64 as standard library, which is an open source implementation of Windows API.
So GCC+MinGW will use its own headers and will not look for any Windows SDK. So GCC+MinGW on Windows works without having any Microsoft developer tools installed at all.
MinGW-w64 - which is more recent than MinGW and which supports both Windows 32-bit and 64-bit - exists in a standalone package that can be downloaded from https://winlibs.com/. But you can still use it from an IDE like VSCode or Code::Blocks.
MinGW-w64 has the files like knownfolders.h and processthreadsapi.h which you had issues with.
But be aware that #pragma comment(lib, "user32.lib") is MSVC-specific and will not work in other compilers like GCC. Instead you must use linker flag -luser32. Because you call CoTaskMemFree() you will also need to add -lole32.
I tried your code on my system and it compiles and links fine with:
gcc -c -o Documents_path.o Documents_path.c
gcc -o Documents_path.exe Documents_path.o -luser32 -lole32

Can you have multiple DLLs with common exports/ordinals and exchange at run-time?

I am trying to create a couple of Win32 64-bit DLLs (Windows 10) which have different implementations but consistent symbol exports. The aim for this is that one would link with whichever one at build time but have the option at deployment to install either DLL and correctly run with that. I have achieved this straightforwardly on Linux where I am much more comfortable and familiar with run-time linking. But on Windows, I have not yet managed this and I am wondering if this is possible at all. I am trying this using both VS2010 and VS2019.
Suppose I have two libraries blah_legacy.dll and blah_modern.dll. They both export 6 symbols which are the interface to using the library, e.g. blah_open, blah_read, blah_write, blah_close, blah_control, blah_status.
I can link with the import library for either blah implementation and a test program calling each symbol loads and executes correctly with the corresponding blah DLL.
However, I cannot yet switch the DLLs at run time. For example, should I actually be able to link with blah-legacy.lib and then run with blah-modern.dll if I rename it to blah-legacy.dll? (Or vice-versa.)
I already got around basic file-naming issues and ensured the DLL needed can actually be found. I still got the application failed to start (0x22).
I used "objdump -xs" on the DLLs and noticed the order of symbols and their ordinals are different. So I created a .def file and ensured that the exported symbols match in number, names and in ordinals. Still nothing - the same error occurs.
There's still something to this I clearly have not figured out and would appreciate some guidance. Is this actually possible? Where do I start to look (which tools) to figure out what step to take next.
Yes.
I don't use Visual Studio much, but this is the kind of thing that happens all the time if you use MSYS2, and install some MinGW packages, and update them.
Here's what I mean by that: MSYS2 is an open source software distribution for Windows that, among other things, provides a bunch of native Windows software packages. The package manager (pacman) let's you choose which packages to have in your system, and it downloads DLLs and EXEs that were created by the MSYS2 developers. When an MSYS2 developer updates a library, you can download the updated library package, and all the other packages using that library will automatically start using the new DLL. Usually there is no issue with that because the new library version will be ABI-compatible with the old library version.
You do not need to use LoadLibrary or otherwise mess up your source code; the linker and the operating system should be able to take care of this for you.
Example
Here is a minimal example I threw together with MSYS2 showing how this can work.
The file foo_legacy.c represents your legacy DLL. I added some extra symbols so it wouldn't be too similar to the modern DLL.
__declspec(dllexport) int eoo() {
return 0;
}
__declspec(dllexport) const char * foo_name() {
return "legacy";
}
__declspec(dllexport) int foo_version() {
return 1;
}
__declspec(dllexport) int goo() {
return 0;
}
The file foo_modern.c represents the modern implementation:
__declspec(dllexport) const char * foo_name(void);
__declspec(dllexport) int foo_version(void);
int foo_version() {
return 2;
}
const char * foo_name() {
return "modern";
}
The file main.c represents an application using the foo API:
#include <stdio.h>
__declspec(dllimport) const char * foo_name(void);
__declspec(dllimport) int foo_version(void);
int main()
{
printf("%s %d\n", foo_name(), foo_version());
}
My build.sh file is a Bash script that builds and tests everything:
#!/usr/bin/bash
set -uex
gcc -Wall foo_legacy.c -shared -o foo_legacy.dll
gcc -Wall foo_modern.c -shared -o foo_modern.dll
gcc -Wall -c main.c -I. -o main.o
gcc main.o foo_legacy.dll -o main.exe
./main.exe # output: "legacy 1"
mv foo_modern.dll foo_legacy.dll
./main.exe # output: "modern 2"
rm foo_legacy.dll
./main.exe # fails because foo_legacy.dll is not found
The build script runs main.exe three different times, showing that it can either use the legacy DLL, or use the modern DLL, or fail, depending on what was installed in foo_legacy.dll.

Fail to find a function in yaml.h library (C)

I try to read a yml file in C (Code::Blocks IDE) but I receive an undefined reference error for yaml_parser_initialize:
#include <stdio.h>
#include <stdlib.h>
#include <yaml.h>
int main(){
FILE *fh = fopen("configuration.yaml", "r");
yaml_parser_t parser;
/* Initialize parser */
if(!yaml_parser_initialize(&parser))
fputs("Failed to initialize parser!\n", stderr);
fclose(fh);
return 0;}
The function exists in yaml.h. I linked the yaml library as follows:
Project->Build Options->Linker Settings: added src\.libs\libyaml.a
Project->Build Options->Search Directories->Compiler: added the include library: yaml-0.2.5\include.
Project->Build Options->Search Directories->Linker: added the include library: yaml-0.2.5\include.
OS: Win10
Thanks in advance.
In short, I will try to answer that and update my answer per request.
If you building on Linux OS, no matter if your host OS is Windows(you may run Linux as a virtual machine), you usually link with .a or .so library files.
If you build envinronment is Windows, no matter the host OS, then you usually link with .lib or .dll libraries.
That being said, the above mentioned OS'es have a different convention about how to supply a path to file.
On Linux the path go like this: /path/to/libs/libyaml.a.
On Windows the path go like this C:\Program Files\libs\yaml.lib.
Any app that runs on the OS follow the OS path convention. In your case Code::Blocks request you to supply a path in the convention the guest OS is.
The below text, is two methods of building your code with yaml library ob Ubuntu.
Update
I do not use Code::Blocks as of now. I've installed the IDE to check what your options are.
You talk about Ubuntu, C and yaml. That will be:
1) New Project->Console Application->C.
2) <Whichever project names you wish>
3) <Whatever compiler configuration you like>
That was to create a bunch of files that CB calls project. Now I dont know what sort of yaml library you use. But you talk about Ubuntu and C so...
1) apt search libyaml-><guess what yaml are>->apt install libyaml-dev
2) pkg-config --list-all | grep yaml gets me the output of yaml-0.1. That is the name I want to supply as argument to pkg-config.
BTW you seem to get a different version of yaml library. But still, all we need is to know proper strings to supply as compiler and linker arguments.
3) pkg-config --libs gets me -lyaml
4) pkg-config --cflags gets me empty line. So the include path is well-known for the build envinronment
This way, we know the linker arguments(-lyaml) and the compiler arguments(<empty string>). Now I try to insert them somewhere where CB could find them.
1) Menu options: Project->Build options...
2) Compiler settings-> no change
3) Linker settings->link libraries->yaml
The libraries in CB should go without -l prefix, so it should be as above. Hit build and all went OK.
Update for git version
It seems that your yaml version is newer than my distro version. If you need recent version, lets go and install that from git.
1) apt remove libyaml-dev. So that there will be no clashes with the library versions.
I did choose the Canonical repository for libyaml as my distro is Ubuntu. You need to mkdir for the sources and cd to that directory.
2) git clone https://github.com/yaml/libyaml
3) cd libyaml
4) Follow the instructions to build and install.
5) pkg-config --list-all | grep yaml gets me yaml-0.1
6) pkg-config --cflags yaml-0.1 produces -I/usr/local/include
7) pkg-config --libs yaml-0.1 gets this -L/usr/local/lib -lyaml
Ok we got the compiler & linker flags for the library. The link library option stays the same. You need to add -L/usr/local/lib to Other linker options. I did not find where I could add the compiler flags, so I'had added new flag. In CB that will be Compiler flags-><right mouse click>->New flag. Name the flag somehow and insert the -I/usr/local/include string to the Compiler flags input row. Hit OK button. Hit the checkbox in front of your newly created flag. Build & Run.

Lack of debugging information in, well, debugger

Currently I am using Clion IDE plus latest version of Open Watcom v2 windows 32 bit compiler to develop some 16 bit MS-DOS application. The problem I have is I don't see all required debugging information when using watcom windows debugger (wdw.exe).
Being specific, I see global variables, global and any other types of functions, even those imported from asm files. But well, local variables list is empty all the time. But more importantly - the only c-code I can see is little test.c file which contains only main() function and nothing else except for includes.
What do I need to do to finally get c-level debugging for whole project? What am I missing?
I would be grateful for any help.
All source files is located in one directory, so, they all should be visible to debugger. But it sees only main c file.
Of course I am compiling with -d2 switch, as well as -hw. DEBUG WATCOM ALL is also presented in linker config file before any FILE directives. Reading manuals to compiler and linker... Well, it's nice that I've found many interesting things in manuals, but nothing helped with exactly that issue so far :)
List of compiler switches I currently using:
WCC.EXE:
CALL WCC.EXE -dTEST -bt=dos -0 -za99 -wx -we -mc -zp2 -hw -d2
%SRC_FULL_NAME%
WLINK:
CALL WLINK.EXE #..\CC.LK
CC.LK:
SYSTEM DOS
DEBUG WATCOM ALL
FILE TEST.OBJ
FILE LUTILS.OBJ
FILE LGL.OBJ
NAME TEST.EXE
OPTION ELIMINATE
...

Problems with linking a library with a c program in linux

I want to run serial commands from a Bealgebone to a 4Dsystems display. Therefore I copied the c library found here into a directory and created a test program main.c:
#include "Picaso_const4D.h"
#include "Picaso_Serial_4DLibrary.h"
int main(int argc,char *argv[])
{
OpenComm("/dev/ttyUSB0", B115200); // Matches with the display "Comms" rate
gfx_BGcolour(0xFFFF);
gfx_Cls();
gfx_CircleFilled(120,160,80,BLUE);
while (1) {}
}
Now when I do gcc -o main main.c its says
main.c:2:37: fatal error: Picaso_Serial_4DLibrary.h: No such file or
directory
So I try linking it:
gcc main.c -L. -lPICASO_SERIAL_4DLIBRARY
which gives me the same error. Then I tried to create a static library:
gcc -Wall -g -c -o PICASO_SERIAL_4DLIBRARY PICASO_SERIAL_4DLIBRARY.C
which gives me this:
PICASO_SERIAL_4DLIBRARY.C:1:21: fatal error: windows.h: No such file
or directory compilation terminated.
What am I doing wrong? the git page clearly says this library is created for people who do not run windows.
Thanks in advance!
You're not getting a linker error; you're getting a preprocessor error. Specifically, your preprocessor can't find Picaso_Serial_4DLibrary.h. Make sure that it's in your include path; you can add directories to your include path using the -I argument to gcc.
You've had two problems. First was the picaso_whatever.h file that couldn't be found. You fixed that with the -I you added. But, now, the picaso.h wants windows.h
What are you building on? WinX or BSD/Linux?
If you're compiling on WinX, you need to install the "platform sdk" for visual studio.
If you're using mingw or cygwin, you need to do something else.
If on WinX, cd to the C: directory. Do find . -type f -name windows.h and add a -I for the containing directory.
If under Linux, repeat the find at the source tree top level. Otherwise, there is probably some compatibility cross-build library that you need to install.
Or, you'll have to find WinX that has it as Picaso clearly includes it. You could try commenting out one or more of the #include's for it and see if things are better or worse.
If you can't find a real one, create an empty windows.h and add -I to it and see how bad [or good] things are.
You may need the mingw cross-compiler. See https://forums.wxwidgets.org/viewtopic.php?t=7729
UPDATE:
Okay ... Wow ... You are on the right track and close, but this is, IMO, ugly WinX stuff.
The primary need of Picaso is getting a serial comm port connection, so the need from within windows.h is [thankfully] minimal. It needs basic boilerplate definitions for WORD, DWORD, etc.
mingw or cygwin will provide their own copies of windows.h. These are "clean room" reimplementations, so no copyright issues.
mingw is a collection of compile/build tools that let you use gcc/ld/make build utilities.
cygwin is more like: I'd like a complete shell-like environment similar to BSD/Linux. You get bash, ls, gcc, tar, and just about any GNU utility you want.
Caveat: I use cygwin, but have never used mingw. The mingw version of windows.h [and a suite of .h files that it includes underneath], being open source, can be reused by other projects (e.g. cygwin, wine).
Under Linux, wine (windows emulator) is a program/suite that attempts to allow you to run WinX binaries under Linux (e.g. wine mywinpgm).
I git cloned the Picaso library and after some fiddling, I was able to get it to compile after pointing it to wine's version of windows.h
Picaso's OpenComm is doing CreateFile [a win32 API call]. So, you'll probably need cygwin. You're opening /dev/ttyUSB0. /dev/* implies cygwin. But, /dev/ttyUSB0 is a Linux-like name. You may need some WinX-style name like "COM:" or whatever. Under the cygwin terminal [which gives you a bash prompt], do ls /dev and see what's available.
You can get cygwin from: http://cygwin.com/ If you have a 64 bit system, be sure to use the 64 bit version of the installer: setup-x86_64.exe It's semi-graphical and will want two directories, one for the "root" FS and one to store packages. On my system, I use C:\cygwin64 and C:\cygwin64_packages--YMMV.
Note that the installer won't install gcc by default. You can [graphically] select which packages to install. You may also need some "devel" packages. They have libraries and .h files that a non-developer wouldn't need. As, docs mention, you can rerun the installer as often as you need. You can add packages that you forgot to specify or even remove ones that you installed that you don't need anymore.
Remember that you'll need to adjust makefile -I and/or -L option appropriately. Also, when building the picaso library, gcc generated a ton of warnings about overflow of a "large integer". The code was doing:
#define control_code -279
unsigned char buf[2];
buf[0] = control_code >> 8;
buf[1] = control_code;
The code is okay, and the warning is correct [because the code is sloppy]. If the code had done:
#define control_code -279
unsigned char buf[2];
buf[0] = (unsigned) control_code >> 8;
buf[1] = (unsigned) control_code;
it probably would have been silent. Use -Wno-overflow in your Makefile to get rid of the warnings rather that edit 50 or so lines

Resources