I have a bash script that compiles a program as well on older versions of Ubuntu (14.04.x and 16.04.x) than on the last one (18.04.x) and on other distributions (Arch, CentOS, Debian, Fedora, etc.) and therefore... with different gcc settings.
Then, to obtain an executable that can be launched (among other ways) by a double click, I must compile this program without the "-no-pie" option with older versions of gcc setting (Ubuntu 14.04.x and 16.04.x) when I have to use this option "=no-pie" for the new version of the gcc 7.3 setting (on Ubuntu 18.04.x).
The problem is that on the last Ubuntu release (18.04.x) and its derivatives (Kubuntu, Xbuntu, etc. and maybe with other distributions) with the new configuration of gcc (7.3) having the option "--enable-default-pie", if I compile my program without the option "-no-pie", the result is that the file created is an executable which is of the "shared library" type which can not be launched by a double click.
My question is either:
a) Is there a command that allows me to determine from a bash script if gcc is configured with the "--enable-default-pie" setting?
b) if not, is there a command that allows me to determine from a bash script if the compiled file is of the "shared library" or "executable" type?
For this second option, a solution could be how to save the response of "gcc -v" in a .txt file and check if there is the "--enable-default-pie" string but I've absolutely no clue how to do it.
If I there is not an answer to my first option, the second option (it is true less elegant but just as effective) would allow me to compile my program first without the "-no-pie" option, then check the status of such a created executable and if the result is a "shared library", of restart this compilation this time using the option "-no-pie" for, in one case as in the other, get an executable that can be launched by a double click whatever the setting of gcc may be.
Thank you in advance for your time, ideas and suggestions.
Best regards.
The recommend way to check for PIE support is to compile C code like this
#if defined __PIC__ || defined __pic__ || defined PIC || defined pic
# error PIC is default.
#endif
with the requested compiler flags and check whether there is an error. If you need special treatment for PIE, this will recognize PIE if it has been specified through the CC or CFLAGS variables, even if is not immediately apparent there. For example, for technical reasons, Fedora hides the PIE flags behind a -specs argument.
Yes, you can check GCC build options with gcc -v or gcc -###
In order to have pretty print you can use:
gcc -### -E 2>&1 | grep "Configured with" | sed 's/--/\n--/g'
So bash oneliner to say you have pie or not may be:
if [[ -n "`gcc -v -E 2>&1 | grep 'Configured with' | sed 's/--/\n--/g' | grep enable-default-spie`" ]]; then echo "PIE DEFAULT"; else echo "PIE NOT DEFAULT"; fi
To check file type just use file command, eg.:
file /usr/bin/x86_64-linux-gnu-gcc-7
/usr/bin/x86_64-linux-gnu-gcc-7: ELF 64-bit LSB executable,
x86-64, version 1 (SYSV), dynamically linked, interpreter
/lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0,
BuildID[sha1]=02ac46ba938c15f55f6fab165133e0f527bc2197, stripped
file /usr/lib/libchm.so.1.0.0
/usr/lib/libchm.so.1.0.0: ELF 64-bit LSB shared object, x86-64,
version 1 (SYSV), dynamically linked,
BuildID[sha1]=7c603d9a0771b5bfd5b869b4446e2f78ef13802a, stripped
File type function
function whatfile { file $1 -i | grep application | sed 's/^.*application\/x-//g;s/,.*$//g'; }
Example output:
aaa#xxx:~ $ whatfile /boot/grub/grub.conf
aaa#xxx:~ $ whatfile /usr/lib/libnss3.so
sharedlib
aaa#xxx:~ $ whatfile /bin/zcat
executable
Unfortunately, comments don't allow CR+LF (to show pre-formatted text).
Below is my formatted translation of your gcc setting command:
check_gcc_setting()
{
if [ -n "`gcc -v -E 2>&1 | grep 'Configured with' | sed 's/--/\n--/g' | grep enable-default-pie`" ]
then
GCC_SETTING="1"
else
GCC_SETTING="0"
fi
read -p "The gcc setting is $GCC_SETTING " GCCRESULT
}
Below is the result:
whatfile { file $1 -i | grep application | sed 's/^.*application\/x-//g;s/,.*$//g'; }
-bash: syntax error near unexpected token `}'
Related
As the question says, im wondering how to get the linux and gcc versions from the proc file. I know that I have to use cat /proc/version but the result is too much of (to me) unnecessary information. If I run the command I get this: MINGW64_NT-10.0-19042 version 3.1.6-340.x86_64 (#fv-az314) (gcc version 9.3.0 (GCC) ) 2020-07-09 14:33 UTC(the command was run in cmder bash.exe). What I want instead is to only get 3.1.6-340.x86_64(linux version) and 9.3.0(gcc version). I understand there are certain commands that allow for this sort of info extraction but as i am new to bash scripting I don't know how to go about doing that. My wanted output is: Linux: <linux version> \n gcc: <gcc version> (where \n is the new line character).
Any and all help is apreciated.
I kept your "formatting", though I'm not sure that's what you actually want.
awk '{printf "Linux: %s \n gcc: %s", $3, gensub(/^.*gcc version ([^ ]+).*$/, "\\1","1",$0)}' /proc/version
Linux: 5.4.0-72-generic
gcc: 9.3.0tink#linux:~
The code would be :
var1=$(uname -r)
var2=$(gcc -dumpversion)
echo -e "Linux version is $var1 \n gcc version is $var2"
This should give you your required output
Does anybody know any cmake variable or hook or something which can give me underlying platform name/flavour name on which it is getting executed ?
e.g. Linux-CentOs
Linux-Ubuntu
Linux-SLES
I know cmake has "CMAKE_SYSTEM" variable but that doesn't help differentiating flavours of linux for e.g. Any help is appreciated.
edit :
I just read that it can be done using lsb_release command ?
The following snippet populates the LSB_RELEASE_ID_SHORT cmake variable with information about the underlying Linux system:
find_program(LSB_RELEASE_EXEC lsb_release)
execute_process(COMMAND ${LSB_RELEASE_EXEC} -is
OUTPUT_VARIABLE LSB_RELEASE_ID_SHORT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
On Ubuntu, for example, it yields Ubuntu.
Slightly less convoluted than checking files on the filesystem is to deduce the best you can from the available CMAKE_SYSTEM vars. For instance a CMakeLists.txt file containing lines like this:
message("-- CMAKE_SYSTEM_INFO_FILE: ${CMAKE_SYSTEM_INFO_FILE}")
message("-- CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
message("-- CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
message("-- CMAKE_SYSTEM: ${CMAKE_SYSTEM}")
string (REGEX MATCH "\\.el[1-9]" os_version_suffix ${CMAKE_SYSTEM})
message("-- os_version_suffix: ${os_version_suffix}")
outputs this when I ran cmake . :
-- CMAKE_SYSTEM_INFO_FILE: Platform/Linux
-- CMAKE_SYSTEM_NAME: Linux
-- CMAKE_SYSTEM_PROCESSOR: x86_64
-- CMAKE_SYSTEM: Linux-2.6.32-573.7.1.el6.x86_64
-- os_version_suffix: .el6
And for my situation, the .el6 was enough to differentiate.
Likely, you have to write such a test yourself. Here's one of the possible examples, just googled: https://htcondor-wiki.cs.wisc.edu/index.cgi/fileview?f=build/cmake/FindLinuxPlatform.cmake&v=4592599fecc08e5588c4244e2b0ceb7d32363a56
However depending on your actual needs the test may be quite complex. For example Ubuntu as a Debian-based OS always has /etc/debian_version and many RPM-based OSes traditionally have /etc/redhat-release. There's a file /etc/os-release in the Linux Standard Base (LSB) specification, but for example on the localhost this file is empty for an unknown reason :)
I know this is an old question, but as of now, there is still no cmake built-in function to find this information in good detail. I've implemented a small utility function that uses lsb_release on Linux to find a number of relevant system details:
function(get_linux_lsb_release_information)
find_program(LSB_RELEASE_EXEC lsb_release)
if(NOT LSB_RELEASE_EXEC)
message(FATAL_ERROR "Could not detect lsb_release executable, can not gather required information")
endif()
execute_process(COMMAND "${LSB_RELEASE_EXEC}" --short --id OUTPUT_VARIABLE LSB_RELEASE_ID_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND "${LSB_RELEASE_EXEC}" --short --release OUTPUT_VARIABLE LSB_RELEASE_VERSION_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND "${LSB_RELEASE_EXEC}" --short --codename OUTPUT_VARIABLE LSB_RELEASE_CODENAME_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE)
set(LSB_RELEASE_ID_SHORT "${LSB_RELEASE_ID_SHORT}" PARENT_SCOPE)
set(LSB_RELEASE_VERSION_SHORT "${LSB_RELEASE_VERSION_SHORT}" PARENT_SCOPE)
set(LSB_RELEASE_CODENAME_SHORT "${LSB_RELEASE_CODENAME_SHORT}" PARENT_SCOPE)
endfunction()
Add it to your CMakeLists.txt and use it like this:
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
get_linux_lsb_release_information()
message(STATUS "Linux ${LSB_RELEASE_ID_SHORT} ${LSB_RELEASE_VERSION_SHORT} ${LSB_RELEASE_CODENAME_SHORT}")
endif()
If you need further details, check what else lsb_release can provide with lsb_release -a.
Note that not every Linux has lsb_release installed. Most systems provide it, but its not mandatory. On newer Ubuntu, for example, its the default on desktop installs, and required by ubuntu-minimal. If it should be missing on your machine, you can install it with sudo apt install lsb-release.
on my machine
CMAKE_SYSTEM_INFO_FILE == "Platform/Linux"
CMAKE_SYSTEM_NAME == "Linux"
CMAKE_SYSTEM == "Linux-<kernel version>"
obtained with cmake --system-information, I know of people that use said macros in their own CMakeLists.txt files so they work as expected, probably CMAKE_SYSTEM_NAME is what you really want but here you go, you get this 3 and the command to inspect the properties of your machine as far as cmake is concerned .
Based on thiagowfx answer, If you want to get the codename of the distro (if it is available):
execute_process(COMMAND lsb_release -cs
OUTPUT_VARIABLE RELEASE_CODENAME
OUTPUT_STRIP_TRAILING_WHITESPACE
)
E.g. in Ubuntu 14.04 the variable RELEASE_CODENAME will hold trusty.
### find our os (wins, centos, ubuntu, etc)
set(VAR_OS "")
IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
MESSAGE(DEBUG "Linux")
execute_process (
COMMAND bash -c "awk -F= '/^ID=/{print $2}' /etc/os-release |tr -d '\n' | tr -d '\"'"
OUTPUT_VARIABLE outOS
)
MESSAGE(DEBUG "Linux os: ${outOS}")
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Windows")
MESSAGE(DEBUG "Windows")
set(VAR_OS "wins")
ELSE()
MESSAGE(FATAL "No OS detected!")
ENDIF(CMAKE_SYSTEM_NAME MATCHES "Linux")
I am trying to run Ymer tool in windows 10 platform. I have installed g++, gcc, yacc via cygwin. After configure command, When I am running make command to compile the application, it generates following error.
PS C:\ymer> make
/bin/sh ./ylwrap src/grammar.yy y.tab.c src/grammar.cc y.tab.h echo src/grammar.cc | sed -e s/cc$/hh/ -e s/cpp$/hpp/ -e s/cxx$/hxx/ -e s/c++$/h++/ -e s/c$/h/ y.output src/grammar.output -- byacc -d
byacc: e - line 514 of "/cygdrive/c/ymer/src/grammar.yy", syntax error
%defines
^
Makefile:2467: recipe for target 'src/grammar.cc' failed
make: *** [src/grammar.cc] Error 1
It seems the grammar.yy file causes the problem. Anyone knows how to solve this problem. BTW I am not familiar neither with yacc nor make files. I am just very new to cygwin as well.
Thank you,
The %defines declaration is bison-specific (not part of standard yacc). The file grammar.yy contains some bison features which byacc implements, but this is not one of those. (From the description in the manual page, it seems that this is equivalent to the standard command-line option -d, making it less than useful).
I complied a linux program on windows via Mingw. However, the output of the program looks different on Windows than on Linux.
For example, on Windows the output is this (I get 'zu' instead of real numbers):
Approximated minimal memory consumption:
Sequence : zuM
Buffer : 1 X zuM = zuM
Table : 1 X zuM = zuM
Miscellaneous : zuM
Total : zuM
On Linux, the original program compiles (without Mingw) with a warning. On Windows, under Mingw, it compiles with zero warnings.
There is anything I should be aware about?
Does Mingw offer 100% compatibility or I have to modify the program to work on Win?
I don't know in which direction to head. Where should I start my attempt of fixing the program?
Do you think I have better chances with Cygwin?
Update:
Wikipedia mentions this: "the lack of support for C99 has caused porting problems, particularly where printf-style conversion specifiers are concerned".
Is this the thing in which I bumped my head?
Update:
My mingw version is:
MINGWBASEDIR=C:\MinGW
gcc version 4.8.1 (GCC)
gcc version 4.8.1 (GCC)
GNU gdb (GDB) 7.6.1
GNU ld (GNU Binutils) 2.24
GNU windres (GNU Binutils) 2.24
GNU dlltool (GNU Binutils) 2.24
GNU Make 3.82.90
#define __MINGW32_VERSION 3.20
#define __W32API_VERSION 3.17
(I used this code to get the version:
#echo off
REM version-of-mingw.bat
REM credit to Peter Ward work in ReactOS Build Environment RosBE.cmd it gave me a starting point that I edited.
::
:: Display the current version of GCC, ld, make and others.
::
REM %CD% works in Windows XP, not sure when it was added to Windows
REM set MINGWBASEDIR=C:\MinGW
set MINGWBASEDIR=%CD%
ECHO MINGWBASEDIR=%MINGWBASEDIR%
SET PATH=%MINGWBASEDIR%\bin;%SystemRoot%\system32
if exist %MINGWBASEDIR%\bin\gcc.exe (gcc -v 2>&1 | find "gcc version")
REM if exist %MINGWBASEDIR%\bin\gcc.exe gcc -print-search-dirs
if exist %MINGWBASEDIR%\bin\c++.exe (c++ -v 2>&1 | find "gcc version")
if exist %MINGWBASEDIR%\bin\gcc-sjlj.exe (gcc-sjlj.exe -v 2>&1 | find "gcc version")
if exist %MINGWBASEDIR%\bin\gcc-dw2.exe (gcc-dw2.exe -v 2>&1 | find "gcc version")
if exist %MINGWBASEDIR%\bin\gdb.exe (gdb.exe -v | find "GNU gdb")
if exist %MINGWBASEDIR%\bin\nasm.exe (nasm -v)
if exist %MINGWBASEDIR%\bin\ld.exe (ld -v)
if exist %MINGWBASEDIR%\bin\windres.exe (windres --version | find "GNU windres")
if exist %MINGWBASEDIR%\bin\dlltool.exe (dlltool --version | find "GNU dlltool")
if exist %MINGWBASEDIR%\bin\pexports.exe (pexports | find "PExports" )
if exist %MINGWBASEDIR%\bin\mingw32-make.exe (mingw32-make -v | find "GNU Make")
if exist %MINGWBASEDIR%\bin\make.exe (ECHO It is not recommended to have make.exe in mingw/bin)
REM ECHO "The minGW runtime version is the same as __MINGW32_VERSION"
if exist "%MINGWBASEDIR%\include\_mingw.h" (type "%MINGWBASEDIR%\include\_mingw.h" | find "__MINGW32_VERSION" | find "#define")
if exist "%MINGWBASEDIR%\include\w32api.h" (type "%MINGWBASEDIR%\include\w32api.h" | find "__W32API_VERSION")
:_end
PAUSE
)
As suggested by the bug report discussion linked in the comments, Microsoft's printf functions do not support C99. The mingw-w64 project provides alternative functions that may be used as if they were the normal C99 functions if the macro __USE_MINGW_ANSI_STDIO is set to 1 either before including any headers or on the command line. They support the standard %zu, %jd, etc. format specifiers that even the newest MSVCRT versions do not. You may invoke the function directly using mingw_printf, but it is usually easier to just define the aforementioned macro to 1 and call printf, etc.
It is worth noting that if you use Microsoft's snprintf, it will return -1 to indicate truncation if the buffer is not large enough, unless the buffer and buffer size parameters are NULL and 0 respectively, in which case the number of bytes that would be output is returned. C99 behavior is to always return the number of bytes that would be output if the buffer was sufficiently large, or a negative value if an encoding error occurs, and the mingw-w64 implementation seems to behave correctly according to C99.
And all you need to do to get all of this standard behavior is either #define __USE_MINGW_ANSI_STDIO 1 before any includes if you use any of the printf functions or simply add -D__USE_MINGW_ANSI_STDIO=1 to your compiler invocation.
If you are worried about the macro interfering with other platforms, no other implementation except the original (legacy?) MinGW[32] project that provided similar functionality should actually make use of this preprocessor macro, so it is safe to define it unconditionally.
I have a linux makefile that needs to compile on 2 different kernel versions. The makefile is not generated from automake/autoconf.
The C code are already conditioned using macros to generate different code for different kernel version, but certain features in the makefile needs to be also conditioned.
Is there a way in a makefile to do:
if (kernel_version > 2.6.30)
newer_kernel = 1
else
newer_kernel = 0
endif
Well, I can think of one quick way to do it with bash:
KERNEL_VERSION=`uname -r`
HIGHER_VERSION=`echo -e "$KERNEL_VERSION\n2.6.30" | sort -g -t '.' | tail --lines=1`
if [ "$HIGHER_VERSION" == "2.6.30" ]
# its an older kernel
else
# its a newer kernel
fi
Basically, you use uname to obtain the version of the current kernel, then compare it to 2.6.30 using sort (the -g flag enables numeric sorting, -t '.' means use dot as a field separator), then use tail to determine which of the two version was higher in the list. Not exactly a beautiful solution, but it will work.
You can put it into a separate script or directly into the makefile recipe