Getting locale functions to work in glibc - c

I need to make some modifications to the the C standard library (glibc) in order to get some performance improvements. Specifically, I am going to be writing some specialized versions of some of the locale-dependent functions (which in glibc perform poorly), such as strcoll.
I have checked out the glibc source from here, into ~/Desktop/glibc. I then ran the following sequence of commands without error.
$ cd ~/Desktop
$ mkdir bglibc
$ cd bglibc
$ ./../glibc/configure --prefix=~/Desktop/bglibc
$ make
$ make install
At this point, I have successfully compiled and installed glibc into ~/Desktop/bglibc. I then created the following test program (ct.c) in the bglibc directory:
#include <stdio.h>
#include <locale.h>
int main ()
{
char *locale = NULL;
locale = "en_US.utf8";
char *result = setlocale(LC_COLLATE, locale);
if (result == NULL) {
printf("locale not set\n");
}
printf("strcoll: %d\n", strcoll("some", "string"));
return 0;
}
I then build it with this script:
iSYSROOT=~/Desktop/bglibc
gcc -o ct ct.c \
--sysroot=${SYSROOT} \
-Wl,-rpath=${SYSROOT}/lib \
-Wl,--dynamic-linker=${SYSROOT}/lib/ld.so.1
Which builds it properly. I then run it with this script:
#!/bin/sh
builddir=`dirname "$0"`
GCONV_PATH="${builddir}/iconvdata" \
exec "${builddir}"/elf/ld-linux-x86-64.so.2 --library-path "${builddir}":"${builddir}"/*:"${builddir}"/*/*:"${builddir}"/*/*/* ${1+"$#"}
Which is names testrun.sh. To run it on the program I previously compiled (ct), I run ./testrun.sh ./ct.
This successfully runs the program, however the program prints out locale not set, meaning that it was unable to set the locale to "en_US.utf8". Thus, the locale keeps the default ("C"), in which case strcoll simply returns the result of strcmp. However, I need this call to run the strcoll code in order to run tests on its performance, and then tune it to run faster for specific locales.
I know that "en_US.utf8" is a valid locale for my system (Ubuntu 12.04 lts), because I see this:
$ locale -a | grep US
en_US.utf8
I have also tried running this program but setting the locale variable to other strings such as "en_US.UTF-16", "", "en_US.UTF-8", etc. all with no luck.
I imagine this isn't the first issue I will run into when trying to get locale stuff to work with my modified version of glibc, but its the first.
Any ideas On what I can do to get the locale functions (specifically setlocale) to work right?

My guess: You forgot to "make" some locales. Try:
$ make
$ make install
$ make localedata/install-locales
see also GNU libc make manual
After installation you might want to configure the timezone and locale
installation …

Try to use the strace to find out where the glibc tries to read the locales from. I suspect that since you set the prefix glibc tries to find them in ~/Desktop/bglibc/share/locale/ or something similar. And certainly UTF-16 will not work with 8 bit string types...

Related

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

How to know if a C program supports an option

I'm developing a script that checks the version of some installed C programs. The version check is performed with the --version option. However, this option may not be implemented in all the checked programs. When the option is implemented I use:
version=$(./$program_name --version)
But when it's not, the program just starts executing.
If I just execute the program in the background and the stop it if continues running, I can never get the version number. Is there a way to check whether the option is implemented without letting the program run?
Not completely waterproof but I nice start is using strings:
strings /usr/bin/git | grep -- --version
If you are referring to any arbitrary C program, no there is currently no way to reliably check if a program supports an option. You can try guessing with a mixture of ./program --help, ./program --usage, ./program -h and ./program --this-option-is-a-lie-or-some-other-bogus-option-to-give-usage-information. However, it all ultimately boils down to guesswork.
On RedHat and derivates using yum and rpm you can ask the rpm package manager:
$ rpm -q --whatprovides /bin/cat
coreutils-8.4-31.el6_5.1.i686
On Debian and derivated using apt-get you can ask the APT package manager:
$ dpkg-query -S /bin/bash
bash: /bin/bash
Back in the day we always included a what string with version info. Actually part of SCCS, if the program contained strings starting with "#(#)", it is displayed by the what command. C code would like like this:
static char prog_id[] = "#(#) my_program version 1.0 - 3/26/2014";
Anyway try doing a what on the program and see what you get. heh.

C - program compiling, but unable to provide arguments

I'm on a Mac and in terminal I'm compiling my program
gcc -Wall -g -o example example.c
it compiles (there are no errors), but when I try to provide command line arguments
example 5 hello how are you
terminal responds with "-bash: example: command not found"
how am supposed to provide the arguments I want to provide after compiling?
Run it like this with path:
./example 5 hello how are you
Unless the directory where the example binary is part of the PATH variable, what you have won't work even if the binary you are running is in the current directory.
It is not a compilation issue, but an issue with your shell. The current directory is not in your PATH (look with echo $PATH and use which to find out how the shell uses it for some particular program, e.g. which gcc).
I suggest testing your program with an explicit file path for the program like
./example 5 hello how are you
You could perhaps edit your ~/.bashrc to add . at the end of your PATH. There are pro and conses (in particular some possible security issues if your current directory happens to be sometimes a "malicious" one like perhaps /tmp might be : bad guys might put there a gcc which is a symlink to /bin/rm so you need to add . at the end of your PATH if you do).
Don't forget to learn how to use a debugger (like gdb). This skill is essential when coding in C (or in C++). Perhaps consider also upgrading your gcc (Apple don"t like much its current GPLv3 license so don't distribute the recent one; try just gcc -v and notice that the latest released GCC is today 4.8.1).
./example 5 Hello how are you is the syntax you're looking for.
This article lends a good explanation as to why this is important.
Basically, when you hit Enter, the shell checks to see if the first set of characters is an absolute path. If it's not, it checks the PATH variable to find executables with the name of the command you are trying to run. If it's found, it will be run, but otherwise it will crash and burn and you will become very sad.

Getting the GCC include path with GNU Autotools

I'm writing an implementation of the C preprocessor that, when running on Linux, needs to know the path on which to find header files. This can be obtained by running gcc -v. I want to compile the results into the binary of my preprocessor rather than having to invoke gcc -v on every run, so I'm currently thinking of writing a Python script to be run at compile time, that would obtain the path and write it into a small C source file to be included in the build.
On the other hand, I get the impression GNU Autotools is basically the specialist in obtaining system-specific information to be used at build time. Does Autotools have the ability to obtain the #include path in such a way that it can be incorporated as a string into the program being built (as opposed to being used for the build process)? If so, how?
If you want to get the internal include/ directory used by GCC, run the gcc -print-file-name=include command, e.g. in shell syntax
the_gcc_include_dir=$(gcc -print-file-name=include)
This $the_gcc_include_dirdirectory contains files like <stdarg.h> and <stddef.h> and many others.
You also want the include-fixed/ directory, so
the_gcc_include_fixed_dir=$(gcc -print-file-name=include-fixed)
This $the_gcc_include_fixed_dir contains files like <limits.h> and also a useful README
You probably don't need autotools in your case.
I ended up parsing gcc's include path with a Python script:
print 'string gcc_include_path[] = {'
for s in sys.stdin:
if s[0] == ' ':
s = s.strip()
print '\t"'+s+'",'
print '};'
and calling it from Makefile:
echo | cpp -Wp,-v 2>&1 >/dev/null | python include_path.py >include_path

A C program compiled under 32-bit Debian Squeeze causes a segfault on my friend's 64-bit one

Not so long ago I've installed Debian and configured it with my friend's help.
Yesterday I have downloaded GCC 4.4 and I created a simple program to test it out.
This is the code:
#include <stdio.h>
int main () {
int result;
printf ("Hello Wor... Linux! This is my %dst program compiled in Debian.\nHow many is 2+2?\n", 1);
scanf ("%d", &result);
while (result!=4) {
printf ("Oh no! You're not going anywhere until you type the correct result! 2+2 is?\n");
scanf ("%d", &result);
}
printf ("Congrats!\n");
return 0;
}
I've compiled it by typing gcc-4.4 myfile.c in bash. Then I've tried to run the resulting binary file and it worked just as I wanted it to. Then I've sent the binary file to my friend to test it on his PC also. When he tried to run it, he received a segmentation fault message and the program didn't work.
He also uses Debian and his kernel's version is very similar to mine (2.6.32-5-686). The only difference is that his kernel is an amd-64 one (he owns a 64-bit processor, while mine is 32-bit).
Why is this happening? Does it mean that 64-bit Linux users will be unable to run my 32-bit programs? If so, can I compile it in a way which will let them to run it?
Please note that I'm not really experienced with Linux.
he may need a chroot for it.
apt-get install ia32-libs
should work for most cases.
see "Using an IA32 chroot to run 32bit applications" http://alioth.debian.org/docman/view.php/30192/21/debian-amd64-howto.html#id292205
Alternatively, set up your compiler to target 64-bit binaries by following the instructions at the OSDev wiki: In brief:
Set up the new repos in /etc/apt/sources.list
deb http://www.tucs.org.au/~jscott4/debian/ stable main #Primary Mirror. Hosted by University of Tasmania.
Add the signing key:
gpg --recv-keys 0x2F90DE4A
gpg -a --export 0x2F90DE4A | sudo apt-key add -
Update your repo indices and get the appropriate cross-compilation package:
apt-get update
apt-get install osdev-crosscompiler-x86-64-elf
Then use the x86_64-elf variant of gcc to target x64. For instance
x86_64-elf-gcc --pedantic -Wall -o foo foo.c
(In fact all the GCC tools and Binutils will have an x86_64-elf- variant now.)
EDIT -- Vastly improved instructions by pulling from a reference instead of from memory.
EDIT -- removed stale mirror
chroot is one option. But remember it requires a lot of disk space as it installs 32-bit libraries.
Alternatively you can compile your file for a 64-bit environment by using the -m64 compiler flag of gcc which sets int to 32 bits and long and pointer to 64 bits and generates code for AMD's x86-64 architecture.

Resources