The binary windows installer for clang includes scan-build but when you run it with msbuild nothing happens. Even if I do something like:
"C:\Program Files\LLVM\bin\scan-build.bat" "C:\Program Files\LLVM\bin\clang.exe" test.cpp
I get something like:
scan-build: Using 'C:\Program Files\LLVM\bin\clang.exe' for static analysis
scan-build: Removed Directory '....'
scan-build: No Bugs found
Where test.cpp is:
void DivideByZero(int z){
if (z == 0) {
int x = 1 / z;
}
}
int main() {
int *i = nullptr;
*i = 42;
DivideByZero(0);
}
If I use the following I get some warnings:
"C:\Program Files\LLVM\bin\clang.exe" --analyze test.cpp
So back to my question. How does one get this to work with MSBUild? What is scan-build actually doing and should I use it or --analyze? What is the difference?
Related
I want to Create a Static-Library from Ada-Code and deploy it to Developers without the GNAT-Toolchain (for C/C++ Code).
I will get following Linker-Errors when I try to Link Ada-Library ('.a') with a C-Program:
undefined reference to `__gnat_rcheck_CE_Overflow_Check'
undefined reference to `ada__text_io__put_line__2'
How can I achieve this ? It seams that I should link against the Runtime-library, but how ?
Test-Code:
main.c:
#include <stdio.h>
extern void adaTest();
extern int add5(int);
int main(){
adaTest();
int b = add5(2);
printf("--> %d \ndone.\n", b);
return 0;
}
ada_lib_project.gpr:
library project ada_lib_project is
for Languages use ("Ada");
for Library_Name use "My_Ada_Lib";
for Library_Dir use "my_generated_lib";
for Library_Kind use "Static";
end ada_lib_project;
adatestpacket.ads:
with Interfaces.C; use Interfaces.C;
package adatestpacket is
procedure adatest with
Export, Convention => C, External_Name => "adaTest";
function add5(x: in int) return int with
Export, Convention => C, External_Name => "add5";
end adatestpacket;
adatestpacket.adb:
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C; use Interfaces.C;
package body adatestpacket is
procedure adatest is
begin
Put_Line("This is executed ADA/SPARK-Code...");
null;
end adatest;
function add5(x: in int) return int is
begin
return x + 5;
end add5;
end adatestpacket;
Compiling:
gcc -c main.c -o main.o # .c -> .o
gprbuild -P ada_lib_project.gpr # .ad[sb] -> .a
gcc main.o -L my_generated_lib -l My_Ada_Lib -o a.out # Linking -- with undefined References
Probably the easiest way to do this is to simply also compile the C source with gprbuild (even if you can't do that in your target scenario, you can do it for testing and see with -v what GPRbuild does to get it to work):
with "ada_lib_project";
project My_Executable is
for Languages use ("C");
for Main use ("main.c");
end My_Executable;
You will also need to call adainit and adafinal to initialize / finalizate Ada packages:
#include <stdio.h>
extern void adainit();
extern void adafinal();
extern void adaTest();
extern int add5(int);
int main(){
adainit();
adaTest();
int b = add5(2);
printf("--> %d \ndone.\n", b);
adafinal();
return 0;
}
adainit and adafinal are generated by gnatbind for standalone libraries. I am not entirely sure whether GPRBuild takes care of this when seeing that you use an Ada library from a C executable; if not you'll need
package Binder is
for Default_Switches ("Ada") use ("-n");
end Binder;
in your library. After doing this, you should be able to do
gprbuild my_executable.gpr
If you want to do it without GPRbuild, the -n/adainit/adafinal part still applies and you need to link your executable with
-l<your-gnat-lib>
where <your-gnat-lib> is the Ada standard library of your GNAT version; last time I did this, it was something like gnat-2021. You may need to add a -L<directory-containing-that-lib> depending on where it's located.
(there may be mistakes in this answer since I cannot currently test it due to being on an M1)
Edit: If you really want to supply developers without any access to GNAT, you need to build an encapsulated, i.e. dynamic, library. This answer covers that process. If providing a static library is a requirement, you have to at least supply the GNAT standard library file.
For anyone whose interested in a Working-Implementation, these are the Changes from my Question:
main.c:
#include <stdio.h>
extern void adainit();
extern void adafinal();
extern void adaTest();
extern int add5(int);
int main(){
adainit();
adaTest();
int b = add5(2);
printf("--> %d \ndone.\n", b);
adafinal();
return 0;
}
ada_lib_project.gpr:
library project ada_lib_project is
for Languages use ("Ada");
for Library_Name use "My_Ada_Lib";
for Library_Dir use "my_generated_lib";
for Library_Kind use "static-pic";
for Library_Interface use ("adatestpacket");
package Binder is
-- "-Lada" set "ada" as Prefix for "init" and "final" Function
for Default_Switches ("Ada") use ("-n","-Lada");
end Binder;
end ada_lib_project;
Compiling:
gprbuild -P ada_lib_project.gpr # .adb -> .a
gcc main.c -L my_generated_lib -l My_Ada_Lib -l gnat_pic -ldl
For the last Command, I just need to Transfer the Library (My_Ada_Lib) and the Runtime (libgnat_pic.a) from GNAT/2021/lib/gcc/x86_64-pc-linux-gnu/10.3.1/rts-native/adalib to the remote Machine.
I have generated static binaries with -static. I don't know if something similar can work while generating your library or you will also need to have the GNAT runtime for linking with the C/C++ tools.
I successfully created a DLL in Haskell. My problem is that everytime I want to compile a test program which loads and uses a function of my DLL I need to copy/paste files from C:\tools\ghc-9.0.1\include in my working directory.
The following files are:
HsFFI.h
ghcconfig.h
ghcautoconf.h
ghcplatform.h
stg/Types.h
I followed the tutorial on their documentation https://downloads.haskell.org/~ghc/7.6.3/docs/html/users_guide/win32-dlls.html but used other compiler commands to make it work.
This is my Adder.hs file
{-# LANGUAGE ForeignFunctionInterface #-}
module Adder where
adder :: Int -> Int -> IO Int
adder x y = return (x+y)
foreign export ccall adder :: Int -> Int -> IO Int
This is my StartEnd.c file to start Haskell runtime
#include <Rts.h>
void HsStart()
{
int argc = 1;
char* argv[] = {"ghcDll", NULL}; // argv must end with NULL
// Initialize Haskell runtime
char** args = argv;
hs_init(&argc, &args);
}
void HsEnd()
{
hs_exit();
}
This is my MyDef.def file to add my functions
EXPORTS
adder
HsStart
HsEnd
I compiled Adder.hs by writing ghc -shared Adder.hs StartEnd.c -o Adder.dll Mydef.def
This is my test.cpp file on c++. I wrote #include "HsFFI.h" to copy/paste HsFFI.h into my working directory as it couldn't find this file by itself when writing #include <HsFFI.h>. I compiled test.cpp by writing g++ -o test test.cpp Adder.dll.a My guess is that i need to make an environment variable so g++ can find this file, but how should i name this variable so g++ can find this file?
#include "HsFFI.h"
#include "Adder_stub.h"
#include <stdio.h>
extern "C" {
void HsStart();
void HsEnd();
}
int main()
{
HsStart();
// can now safely call functions from the DLL
printf("12 + 5 = %i\n", adder(12,5)) ;
HsEnd();
return 0;
}
I used ghc-9.0.1 and windows10.
I have a strange segmentation fault that doesn't exist when everything is in 1 .c file, but does exist when I put part of the code in a dynamically linked library and link it to a test file. The complete code for the working 1 .c file code is at the bottom, the complete code for the error system with 2 .c and 1 .h file come first.
Here is the error system:
example.h:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p);
example.c:
#include "example.h"
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
example2.c:
This is essentially a test file:
#include "example.h"
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here2");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("Start");
test_print();
puts("Done");
return 0;
}
Makefile:
I link example to example2 here, and run:
example:
#clang -I . -dynamiclib \
-undefined dynamic_lookup \
-o example.dylib example.c
#clang example2.c example.dylib -o example2.o
#./example2.o
.PHONY: example
The output is:
$ make example
Start
Here1
Here 8
FOO
make: *** [example] Segmentation fault: 11
But it should show the full output of:
$ make example
Start
Here1
Here 8
FOO
BAR
Here2
Done
The weird thing is everything works if it is this system:
example.c:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("ASF");
test_print();
return 0;
}
Makefile:
example:
#clang -o example example.c
#./example
.PHONY: example
Wondering why it's creating a segmentation fault when it is linked like this, and what I am doing wrong.
I have checked otool and with DYLD_PRINT_LIBRARIES=YES and it shows it is importing the dynamically linked libraries, but for some reason it's segmentation faulting when linked but works fine when it isn't linked.
Your problem is this, in example.h:
MYARRAY *collection;
Since both main.c and example.c include this file, you end up defining collection twice, which results in undefined behavior. You need to make sure you define each object only once. The details are relatively unimportant since anything can happen with undefined behavior, but what's probably happening is that main.c is allocating memory for one object, but the one example.c is using is still NULL. As mentioned in the comments, since you define collection in main.c your linker is able to build the executable without needing to look for that symbol in the dynamic library, so you don't get a link time warning about it being defined there too, and obviously there'd be no cause for a warning at the time you compile the library.
It works for you when you put everything in one file because obviously then you're not defining anything twice, anymore. The error itself is nothing to do with the fact you're using a dynamic library, although that may have made it harder to detect.
It would be better to define this in example.c and provide a constructor function, there's no need for main() to be able to access it directly. But if you must do this, then define it in example.c and just declare an extern identifier in the header file to tell main.c that the object is defined somewhere else.
I've tried adding the following line to the bottom of camera_pipe_generator.cpp to output how Halide compiles into a .html file, but I'm not sure what I'm doing wrong:
processed.compile_to_lowered_stmt("camera_pipe_debugging_trial.html", {}, HTML);
I think my second argument is wrong, but what should I pass in here?
Or is there a different way for me to visualize the schedule? This post seems to suggest a visualizer for Halide exists. Are there any resources available on how to use it?
Thank you!
Edit: I've tried running the command
../../tools/gengen.sh -c c++ -lcurses -l ../../lib/libHalide.a -o tmp/ -e html -s camera_pipe_generator.cpp target=host
However, that resulted in the following error:
Undefined symbols for architecture x86_64:
"_del_curterm", referenced from:
llvm::sys::Process::FileDescriptorHasColors(int) in libHalide.a(llvm_460_Process.cpp.o)
"_set_curterm", referenced from:
llvm::sys::Process::FileDescriptorHasColors(int) in libHalide.a(llvm_460_Process.cpp.o)
"_setupterm", referenced from:
llvm::sys::Process::FileDescriptorHasColors(int) in libHalide.a(llvm_460_Process.cpp.o)
"_tigetnum", referenced from:
llvm::sys::Process::FileDescriptorHasColors(int) in libHalide.a(llvm_460_Process.cpp.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Which I think might be related to running on mac OSX 10.12.3?
Final edit: Added option '-lcurses' to the gengen.sh file and it worked!
To visualize your Halide code to a MPEG file, the following is needed:
Halide filter compiled to AOT binary
Source code to exercise AOT binary
Bash shell script to build and execute HalideTraceViz
All of the above assets in the same folder
Regarding point 4, I'm sure this could altered, but for the trials I had, this was the only way I was able to get things working; anyone who can share their input on that last point is welcome to do so.
1: Halide filter compiled to AOT binary
I used the brighten filter listed on the halide-lang.org tutorial site to create the below listed filter and compile it to a usable binary:
http://halide-lang.org/tutorials/tutorial_lesson_10_aot_compilation_generate.html
#include "Halide.h"
#include <iostream>
namespace
{
auto input = Halide::ImageParam(Halide::type_of< uint8_t >(), 2, std::string{"input_image"});
auto offset = Halide::Param< uint8_t >{"offset"};
} // anonymous namespace
auto create_filter() -> Halide::Func
{
auto x = Halide::Var{"x"};
auto y = Halide::Var{"y"};
auto brighten = Halide::Func{"filter_output"};
brighten(x, y) = input(x, y) + offset;
return brighten;
}
auto schedule_filter(Halide::Func filter_ref) { filter_ref.vectorize(x, 16).parallel(y); }
auto create_aot_binary()
{
auto args = std::vector< Halide::Argument >{input, offset};
brighten.compile_to_file("brighten", args);
}
int main(int argc, const char* argv[])
{
printf("brighten filter AOT binary generator\n");
auto brighten = create_filter();
schedule_filter(brighten);
create_aot_binary();
return 0;
}
2. Source code to exercise AOT binary
#include "brighten.h" // header file created by aot generator in step 1
#include <cassert>
#include <vector>
namespace
{
constexpr auto width = 16 * 4;
constexpr auto height = 16 * 4;
} // anonymous namespace
auto create_input_image() -> std::vector< uint8_t >
{
auto image = std::vector< uint8_t >(width * height, 0);
for (auto y = 0; y < width; y++)
{
for (auto x = 0; x < height; x++)
{
const auto val = x ^ (y + 1);
const auto index = y * height + x;
image[index] = val;
}
}
return image;
}
auto create_buffer_t_with_data(const std::vector< uint8_t >& image) -> buffer_t
{
auto buff = buffer_t{0};
buff.host = image.data();
buff.stride[0] = 1;
buff.stride[1] = width;
buff.extent[0] = width;
buff.extent[1] = height;
buff.elem_size = 1;
}
int main(int argc, const char* argv[])
{
printf("brighten filter exercise\n");
auto input_image = create_input_image();
assert(input_image.size() != 0);
auto input_buf = create_buffer_t_with_data(input_image);
auto output_image = std::vector< uint8_t >(width * height, 0);
assert(output_image.size() != 0);
auto output_buf = create_buffer_t_with_data(output_image);
const auto offset = 1;
auto error = brighten(&input_buf, offset, &output_buf);
(void)error;
return 0;
}
3. Bash shell script to build and execute HalideTraceViz
Now, here is is the bash shell script, where I:
Build the HalideTraceViz.cpp code
Build the AOT generator and filter exerciser app
Copy the binaries into one directory
Call the apps with special parameters that are used for passing data to the HalideTraceViz app
#!/bin/bash
set -e
set -u
function build_binaries()
{
printf "${FUNCNAME[0]}\n"
printf "Building HalideTraceViz\n"
xcodebuild -project visualize_brighten.xcodeproj -scheme HalideTraceViz CONFIGURATION_BUILD_DIR=build/Debug -configuration "Debug" clean build
printf "Building generate_brighten_aot\n"
xcodebuild -project visualize_brighten.xcodeproj -scheme generate_brighten_aot CONFIGURATION_BUILD_DIR=build/Debug -configuration "Debug" clean build
printf "Generating AOT in order to build exercise app\n"
cd build/Debug
HL_TRACE=3 ./generate_brighten_aot
cd $CURRENT_PATH
printf "Building app to exercise brighten filter\n"
xcodebuild -project visualize_brighten.xcodeproj -scheme exercise_brighten_aot CONFIGURATION_BUILD_DIR=build/Debug -configuration "Debug" clean build
cd $CURRENT_PATH
}
function copy_binaries()
{
printf "${FUNCNAME[0]}\n"
if [[ -d $CURRENT_PATH/halide_visualizer ]]; then
rm -Rv $CURRENT_PATH/halide_visualizer
fi
mkdir $CURRENT_PATH/halide_visualizer
cp -Rv $CURRENT_PATH/build/Debug $CURRENT_PATH/halide_visualizer/Debug
}
function visualize_function()
{
printf "${FUNCNAME[0]}\n"
local BLANK=0
local DIMENSIONS=1
local ZOOM=8
local COST=4
local STRIDE0="1 0"
local STRIDE1="0 1"
local FFMPEG_BIN_PATH="YOU_HAVE_TO_DOWNLOAD_THIS_BIN_AND_SET_THE_PATH_HERE"
cd $CURRENT_PATH/halide_visualizer/Debug
echo "About to start visualizing brighten filter"
HL_TRACE=3 ./generate_brighten_aot && \
HL_TRACE_FILE=/dev/stdout ./exercise_brighten_aot | \
$CURRENT_PATH/build/Debug/HalideTraceViz -s 1024 516 -t 1 -d 100 \
-f brighten:input_image 0 255 $BLANK $ZOOM $COST 0 0 $STRIDE0 $STRIDE1 |\
$FFMPEG_BIN_PATH/ffmpeg -r 30 -f rawvideo -pix_fmt bgra -s 1024X516 -i - -y -pix_fmt yuv420p $CURRENT_PATH/movies/brighten_schedule.mp4
cd $CURRENT_PATH
}
main()
{
printf "${FUNCNAME[0]}\n"
CURRENT_PATH=$PWD
build_binaries
copy_binaries
visualize_function
printf "All done\n"
}
printf "Starting ${0##*/}\n"
main
A couple of things to note:
I used Xcode for compiling the projects, but obviously, you can use any tool you are comfortable with
HalideTraceViz comes with it's own cmake file in "Halide/util/"; that folder is part of the Halide git repo
For the bash shell script code, you will have to adjust the folder paths to work with your development setup
All the code that you see listed above was just created now, so I can't guarantee that it works as is :)
Hopefully this helps you get started; if you have any questions, let me know.
toIn the apps/camera_pipe directory, the following command line will generate the HTML stmt file into /tmp/camera_pipe.html:
../../tools/gengen.sh -c c++ -l ../../lib/libHalide.a -o /tmp/ -e html -s camera_pipe_generator.cpp target=host
I am trying to build a static library using MinGW.
Everything was going fine until I tried to use the library and got an error saying that add_numbers is an undefined function.
Many other people have had this problem and sorted it out by moving their library to be linked after the source files were included, but that was how I had written my batch file anyway, so that was not of much help.
Here are my sources.
mylib.h
#ifndef MYLIB_H
#define MYLIB_H
int add_numbers(int a, int b, int c);
#endif
mylib.c
#include "mylib.h"
int add_numbers(int a, int b, int c)
{
return a+b+c;
}
I'm building my .a file with the following commands
gcc --std=c89 -c mylib.c -o mylib.o
ar rcs libmylib.a mylib.o
I've also tried with out specifying the standard.
There are no errors or warnings when running this command.
Next, my test program looks like this.
#include <stdio.h>
#include "mylib.h"
int main()
{
printf("The sum of 1, 2, and 3 is %d", add_numbers(1, 2, 3));
getchar();
return 0;
}
And lastly, we build the test with this command.
gcc mylibtest.c -L -lmylib -o test.exe
I've tried moving around those commands into many many different sequences, but always receiving the following error:
C:\Users\Aaron\AppData\Local\Temp\cc0ERpBi.o:mylibtest.c:(.text+0x26): undefined
reference to `add_numbers'
collect2.exe: error: ld returned 1 exit status
E:\my_first_static_library>
Any help would be very appreciated, I've read every tutorial I could find on the art of writing static libraries, as well as a good ten stackoverflow questions.
You are missing a dot after -L:
gcc mylibtest.c -L . -lmylib -o test.exe