Link clang++ modules: Function exported using C++20 modules is not visible (clang++): Cannot compile executable file that uses module - c++20

I am exporting a function in the following C++20 module. Although the main program can import the module, but it cannot see the exported function:
f1.hpp
export module f1_module;
export void f1() {
}
f1_demo.cpp
import f1_module;
int main() {
f1();
return 0;
}
The build script is:
#!/bin/bash
mkdir -p ./target
FLAGS="-std=c++20 -stdlib=libc++ -fmodules -fbuiltin-module-map"
clang++ $FLAGS \
-fprebuilt-module-path=./target \
-Xclang -emit-module-interface \
-c \
f1.hpp \
-o ./target/f1.module.o
clang++ $FLAGS \
-fprebuilt-module-path=./target \
-fmodule-file=f1_module=./target/f1.module.o \
f1_demo.cpp \
-o ./target/f1_demo.o
The output error: bash build.bash:
ld: error: undefined symbol: f1()
>>> referenced by f1_demo.cpp
>>> /tmp/f1_demo-286314.o:(main)
clang-14: error: linker command failed with exit code 1 (use -v to see invocation)
The exported function f1() is not visible in the main program. How to make it work?
I can provide the output to -v.
I am running above build script in conanio/clang14 docker container:
docker run -it --rm -v $(pwd):/sosi conanio/clang14-ubuntu16.04:latest bash
Update: Cannot link
I tried #DavisHerring 's suggestion, adding -c to the second command, however, it does not generate executable. What I have is a regular object file, and a compiled module file. (The outcome of of -c is not executable). But I need an executable: I cannot link them. When tried to link using clang++, the problem is about linking:
I cannot link an object file with a compiled module file:
clang++ $FLAGS \
-Xclang -emit-module-interface \
-c \
f1_module.cpp \
-o ./target/f1_module.o
clang++ $FLAGS \
-fmodule-file=f1_module=./target/f1_module.o \
-c \
f1_demo.cpp \
-o ./target/f1_demo.o
clang \
-v \
./target/f1_module.o \
./target/f1_demo.o \
-o ./target/exe.o
output:
"/usr/local/bin/ld" -z relro --hash-style=gnu --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o ./target/exe.e /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/local/lib/clang/14.0.0/lib/linux/clang_rt.crtbegin-x86_64.o -L/usr/local/bin/../lib/gcc/x86_64-linux-gnu/10.3.0 -L/usr/local/bin/../lib/gcc/x86_64-linux-gnu/10.3.0/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/local/bin/../lib -L/usr/local/bin/../lib64 -L/lib -L/usr/lib ./target/f1_module.module ./target/f1_demo.o /usr/local/lib/clang/14.0.0/lib/linux/libclang_rt.builtins-x86_64.a --as-needed -l:libllvm-unwind.so --no-as-needed -lc /usr/local/lib/clang/14.0.0/lib/linux/libclang_rt.builtins-x86_64.a --as-needed -l:libllvm-unwind.so --no-as-needed /usr/local/lib/clang/14.0.0/lib/linux/clang_rt.crtend-x86_64.o /usr/lib/x86_64-linux-gnu/crtn.o
followed by error: unclosed quote
ld: error: ./target/f1_module.o:1427: unclosed quote
clang-14: error: linker command failed with exit code 1 (use -v to see invocation)
Note: I am running it on MacBook M1 (arm64) with MacOS Monterey 12.4 and run clang++ via Docker 4.9.1 ( Engine: 20.10.16 ).

You want to compile a module twice. Once to emit a module interface file (which should not have the .o suffix BTW; the customary suffix is .pcm, for "precompiled module") and once to emit an object file (with the customary .o suffix).
clang++ -std=c++20 -c f1_module.cpp -o target/f1_module.o # plain old object
clang++ -std=c++20 -Xclang -emit-module-interface \
-c f1_module.cpp -o target/f1_module.pcm # module interface
Now your module (consisting of two files) is ready, you can use it.
You need to compile the main file against the .pcm file and link the resulting objects against the .o file to produce an executable.
clang++ -std=c++20 -fprebuilt-module-path=./target \
-c f1_demo.cpp -o target/f1_demo.o
clang++ -std=c++20 target/f1_demo.o target/f1_module.o -o target/f1.exe
This is not strictly necessary. With clang, the precompiled module can be used as an object file. The linker however won't recognize it, so clang will need to convert .pcm to .o and feed the temporary .o to the linker, each time you link. This is somewhat of a waste so you may want to eliminate this conversion step by building a separate .o file as above. If you choose not to, you still need to mention the module file on the link line. The simplified process is like this:
clang++ -std=c++20 -Xclang -emit-module-interface \
-c f1_module.cpp -o target/f1_module.pcm # compile module once
clang++ -std=c++20 -fprebuilt-module-path=./target \
-c f1_demo.cpp -o target/f1_demo.o # compile main just as before
clang++ -std=c++20 target/f1_demo.o target/f1_module.pcm \
-o target/f1.exe # mention .pcm explicitly
As far as I know (and I don't know very much), there is currently no way to have clang find out automatically which modules to link against.

Related

Making libtool use another file/directory pattern

How to make libtool don't use (in compile mode) .libs folder for generated PIC object files but another one or even change the name of PIC file, for example: object-file.lo, object-file.o, object-file-pic.o -> these three in one folder.
Standard procedure:
$ libtool --mode=compile gcc -O -o call.o -c called.c
libtool: compile: gcc -O -c called.c -fPIC -DPIC -o .libs/call.o
libtool: compile: gcc -O -c called.c -o call.o >/dev/null 2>&1

How to pass arguments from cmd to tcl script of ModelSim

I run Modelsim in the cmd from a python program.
I use the following code which call a tcl script which run the modelsim:
os.system("vsim -c -do top_tb_simulate_reg.tcl " )
The tcl script contain the following:
vsim -voptargs="+acc" +UVM_TESTNAME=test_name +UVM_MAX_QUIT_COUNT=1 +UVM_VERBOSITY=UVM_LOW \
-t 1ps -L unisims_verm -L generic_baseblocks_v2_1_0 -L axi_infrastructure_v1_1_0 \
-L dds_compiler_v6_0_12 -lib xil_defaultlib xil_defaultlib.girobo2_tb_top \
xil_defaultlib.glbl
I want that the value of the +UVM_TESTNAME will be an argument which I passed from the cmd when I execute:
os.system("vsim -c -do top_tb_simulate_reg.tcl " )
How can I do it?
I tried the following with no succees:
Python script:
os.system("vsim -c -do top_tb_simulate_reg.tcl axi_rd_only_test" )
Simulation file (tcl script)
vsim -voptargs="+acc" +UVM_TESTNAME=$argv +UVM_MAX_QUIT_COUNT=1 +UVM_VERBOSITY=UVM_LOW \
-t 1ps -L unisims_verm -L generic_baseblocks_v2_1_0 -L axi_infrastructure_v1_1_0 \
-L dds_compiler_v6_0_12 -lib xil_defaultlib xil_defaultlib.girobo2_tb_top \
xil_defaultlib.glbl
I got the following error:
# ** Error: (vsim-3170) Could not find 'C:/raft/raftortwo/girobo2/ver/sim/work.axi_rd_only_test'.
The problem is that the vsim binary is doing its own processing of the arguments, and that is interfering. While yes, you can probably find a way around this by reading the vsim documentation, the simplest way around this is to pass values via environment variables. They're inherited by a process from its parent process, and are fine for passing most things. (The exception are security tokens, which should always be passed in files with correctly-set permissions, rather than either environment variables or command-line arguments.)
In your python code:
# Store the value in the *inheritable* environment
os.environ["MY_TEST_CASE"] = "axi_rd_only_test"
# Do the call; the environment gets passed over behind the scenes
os.system("vsim -c -do top_tb_simulate_reg.tcl " )
In your tcl code:
# Read out of the inherited environment
set name $env(MY_TEST_CASE)
# Use it! (Could do this as one line, but that's hard to read)
vsim -voptargs="+acc" +UVM_TESTNAME=$name +UVM_MAX_QUIT_COUNT=1 +UVM_VERBOSITY=UVM_LOW \
-t 1ps -L unisims_verm -L generic_baseblocks_v2_1_0 -L axi_infrastructure_v1_1_0 \
-L dds_compiler_v6_0_12 -lib xil_defaultlib xil_defaultlib.girobo2_tb_top \
xil_defaultlib.glbl
Late to the party but I found a great workaround for your obstacle. The do command within Modelsim's TCL instance does accept parameters. See command reference.
vsim -c -do filename.tcl can't take parameters, but you can use vsim -c -do "do filename.tcl params".
In your case this translates to os.system('vsim -c -do "do top_tb_simulate_reg.tcl axi_rd_only_test"'). Your .tcl script will find the parameter passed through the variable $1.
I hope to helps anyone!

Suppress Specific IP Warnings in Modelsim

A Vivado IP is generating an inordinate amount of Modelsim warnings which are making it difficult to assess the simulation for warnings I actually care about.
I see from the Modelsim command documentation that in order to suppress a warning I need to include the parameter -suppress and then the warning numbers. My current implementation is as follows...
vsim -voptargs=+acc \
-L work \
-L xil_defaultlib \
-L secureip \
-L simprims_ver \
-L unifast_ver \
-L unimacro_ver \
-L unisims_ver \
-L xpm \
-L fifo_generator_v13_1_1 \
-L blk_mem_gen_v8_3_3 \
work.blr_tb xil_defaultlib.glbl -l sv_sim.log -suppress 3015,3017,3722
This code snippet works but I am afraid that this will suppress warnings that are created by problems with my own rtl. Is there a way of suppressing specific warnings of an IP?
For reference the warnings are all from the Vivado MIG IP and look something like this...
# ** Warning: (vsim-3017) ../../ip/xc7k160t2ffg676-2/mig_ddr3_64bit_32G/mig_ddr3_64bit_32G/user_design/rtl/phy/mig_7series_v4_0_ddr_mc_phy_wrapper.v(1260): [TFMPC] - Too few port connections. Expected 9, found 8.
# Time: 0 fs Iteration: 0 Instance: /blr_tb/blr_sbk_top_i/ddr3_balor_i/u_mig_ddr3_64bit_32G/u_mig_ddr3_64bit_32G_mig/u_memc_ui_top_std/mem_intfc0/ddr_phy_top0/u_ddr_mc_phy_wrapper/gen_dqs_iobuf_HP/gen_dqs_iobuf[0]/gen_dqs_diff/u_iobuf_dqs File: C:/Xilinx/Vivado/2016.2/data/verilog/src/unisims/IOBUFDS_DIFF_OUT_DCIEN.v
The MIG is compiled with the following command...
vlog -work xil_defaultlib -incr \
"$SBK_IP_DIR/mig_ddr3_64bit_32G/mig_ddr3_64bit_32G/user_design/rtl/mig_ddr3_64bit_32G.v" \
"$SBK_IP_DIR/mig_ddr3_64bit_32G/mig_ddr3_64bit_32G/user_design/rtl/mig_ddr3_64bit_32G_mig_sim.v" \
"$SBK_IP_DIR/mig_ddr3_64bit_32G/mig_ddr3_64bit_32G/user_design/rtl/clocking/*.v" \
"$SBK_IP_DIR/mig_ddr3_64bit_32G/mig_ddr3_64bit_32G/user_design/rtl/controller/*.v" \
"$SBK_IP_DIR/mig_ddr3_64bit_32G/mig_ddr3_64bit_32G/user_design/rtl/ecc/*.v" \
"$SBK_IP_DIR/mig_ddr3_64bit_32G/mig_ddr3_64bit_32G/user_design/rtl/ip_top/*.v" \
"$SBK_IP_DIR/mig_ddr3_64bit_32G/mig_ddr3_64bit_32G/user_design/rtl/phy/*.v" \
"$SBK_IP_DIR/mig_ddr3_64bit_32G/mig_ddr3_64bit_32G/user_design/rtl/ui/*.v"

Error undefined reference to `cutCreateTimer'

I have the cuda 4.0 toolkit installed in my Ubuntu 12.04 server. When I am trying to build a cuda code present in Rodinia benchmark suite. I was getting the following error. i.e, after running the make command
ncclab#slave13:~/Downloads/rodinia_2.4$ make
cd cuda/cfd; make; cp euler3d euler3d_double pre_euler3d pre_euler3d_double /home/ncclab/Downloads/rodinia_2.4/bin/linux/cuda
make[1]: Entering directory `/home/ncclab/Downloads/rodinia_2.4/cuda/cfd'
nvcc -O2 -Xptxas -v --gpu-architecture=compute_20 --gpu-code=compute_20 euler3d.cu -o euler3d -I/if10/kw5na/NVIDIA_GPU_Computing_SDK4/C/common/inc -L/if10/kw5na/NVIDIA_GPU_Computing_SDK4/C/lib
euler3d.cu:35: warning: #warning "the kernels may fail too launch on some systems if the block length is too large"
euler3d.cu:35: warning: #warning "the kernels may fail too launch on some systems if the block length is too large"
By here the euler3d was built
nvcc -Xptxas -v -O3 --gpu-architecture=compute_20 --gpu-code=compute_20 euler3d_double.cu -o euler3d_double -I/if10/kw5na/NVIDIA_GPU_Computing_SDK4/C/common/inc -L/if10/kw5na/NVIDIA_GPU_Computing_SDK4/C/lib
/tmp/tmpxft_0000532d_00000000-12_euler3d_double.o: In function `main':
tmpxft_0000532d_00000000-1_euler3d_double.cudafe1.cpp:(.text+0x22d9): undefined reference to `cutCreateTimer'
tmpxft_0000532d_00000000-1_euler3d_double.cudafe1.cpp:(.text+0x22f7): undefined reference to `cutStartTimer'
tmpxft_0000532d_00000000-1_euler3d_double.cudafe1.cpp:(.text+0x2457): undefined reference to `cutStopTimer'
tmpxft_0000532d_00000000-1_euler3d_double.cudafe1.cpp:(.text+0x246c): undefined reference to `cutGetAverageTimerValue'
collect2: ld returned 1 exit status
make[1]: *** [euler3d_double] Error 1
make[1]: Leaving directory `/home/ncclab/Downloads/rodinia_2.4/cuda/cfd'
cp: cannot stat `euler3d_double': No such file or directory
cp: cannot stat `pre_euler3d': No such file or directory
cp: cannot stat `pre_euler3d_double': No such file or directory
make: *** [CUDA] Error 1
By searching I came to know that there may be a problem with libcutil
But I had the libcutil_x86_64.a in ~/NVIDIA_GPU_Computing_SDK/C/lib
Edit: The contents of various folders are
ncclab#slave13:~/NVIDIA_GPU_Computing_SDK/C/lib$ ls
libcutil_x86_64.a libparamgl_x86_64.a librendercheckgl_x86_64.a
~/Downloads/rodinia_2.4/cuda/cfd$ ls
euler3d euler3d_double.cu Makefile~ pre_euler3d.cu README
euler3d.cu Makefile Makefile_nvidia pre_euler3d_double.cu run
ncclab#slave13:~/NVIDIA_GPU_Computing_SDK/C/common/inc$ ls
bank_checker.h cutil_inline.h GL nvVector.h stopwatch_base.h
cmd_arg_reader.h cutil_inline_runtime.h multithreading.h nvWidgets.h stopwatch_base.inl
cuda_drvapi_dynlink.c cutil_math.h nvGlutWidgets.h paramgl.h stopwatch.h
cutil_gl_error.h dynlink nvGLWidgets.h param.h stopwatch_linux.h
cutil_gl_inline.h dynlink_d3d10.h nvMath.h rendercheck_d3d10.h
cutil.h dynlink_d3d11.h nvMatrix.h rendercheck_d3d11.h
cutil_inline_bankchecker.h error_checker.h nvQuaternion.h rendercheck_d3d9.h
cutil_inline_drvapi.h exception.h nvShaderUtils.h rendercheck_gl.h
the partial contents of the makefile are
all: euler3d euler3d_double pre_euler3d pre_euler3d_double
euler3d: euler3d.cu
nvcc -O2 -Xptxas -v --gpu-architecture=compute_20 --gpu-code=compute_20 euler3d.cu -o euler3d -I$(CUDA_SDK_PATH)/common/inc -L$(CUDA_SDK_PATH)/lib $(CUTIL_LIB)
euler3d_double: euler3d_double.cu
nvcc -Xptxas -v -O3 --gpu-architecture=compute_20 --gpu-code=compute_20 euler3d_double.cu -o euler3d_double -I$(CUDA_SDK_PATH)/common/inc -L$(CUDA_SDK_PATH)/lib $(CUTIL_LIB)
pre_euler3d: pre_euler3d.cu
nvcc -Xptxas -v -O3 --gpu-architecture=compute_20 --gpu-code=compute_20 pre_euler3d.cu -o pre_euler3d -I$(CUDA_SDK_PATH)/common/inc -L$(CUDA_SDK_PATH)/lib $(CUTIL_LIB)
pre_euler3d_double: pre_euler3d_double.cu
nvcc -Xptxas -v -O3 --gpu-architecture=compute_20 --gpu-code=compute_20 pre_euler3d_double.cu -o pre_euler3d_double -I$(CUDA_SDK_PATH)/common/inc -L$(CUDA_SDK_PATH)/lib $(CUTIL_LIB)
The euler3d has been successfully built. The errors are occurring for all the remaining three files.So I don't think there is any problems in the directories they are referring to
I really don't understand why the undefined reference to `cutCreateTimer' and others are occurring. But searching in SE I came to know that when there is any problem with cutil.h or libcutil these problems exits. I was a newbie of linux environment. So please help me
Edit 2: In a include file named make.config the following lines were present
# CUDA SDK installation path
#SDK_DIR = $(HOME)/NVIDIA_GPU_Computing_SDK/C
SDK_DIR =/if10/kw5na/NVIDIA_GPU_Computing_SDK4/C
#SDK_DIR =/if10/kw5na/NVIDIA_CUDA_Computing_SDK4/C
Here by default the 2nd option was selected and the euler3d was built. So I thought there may be a problem because of this. But changing it does not change the problem I was facing
and about cutil library present in make file
CUDA_SDK_PATH := $(SDK_DIR)
# Determine the correct version of the cutil library
CUTIL_LIB = # -lcutil
ifeq ($(shell uname -m), x86_64)
ifeq ($(shell if test -e $(SDK_DIR)/lib/libcutil_x86_64.a; then echo T; else echo F; fi), T)
CUTIL_LIB = #-lcutil_x86_64
endif
endif
Which I think was correct
The problem is that your compile command is specifying the library path, but not the library itself that is providing the cut... functionality.
This is apparently the makefile line that is generating the nvcc compile command for euler3d_double:
euler3d_double: euler3d_double.cu
nvcc -Xptxas -v -O3 --gpu-architecture=compute_20 --gpu-code=compute_20 euler3d_double.cu -o euler3d_double -I$(CUDA_SDK_PATH)/common/inc -L$(CUDA_SDK_PATH)/lib $(CUTIL_LIB)
This is the generated compile command:
nvcc -Xptxas -v -O3 --gpu-architecture=compute_20 --gpu-code=compute_20 euler3d_double.cu -o euler3d_double -I/if10/kw5na/NVIDIA_GPU_Computing_SDK4/C/common/inc -L/if10/kw5na/NVIDIA_GPU_Computing_SDK4/C/lib
You'll note that the last two tokens in the makefile line are:
-L$(CUDA_SDK_PATH)/lib $(CUTIL_LIB)
The -L$... token is getting converted to the correct library path. But the $(CUTIL_LIB) token should be getting converted to something like -lcutil or perhaps -lcutil_x86_64, but that is not happening. As a result, the library that provides the cut...Timer... functions is missing, and so those appear to be undefined.
I would inspect the Makefile carefully to see if there are any end-of-line characters or other oddities that are different between the line that specifies how euler3d_double should be built and the previous lines that specify how euler3d should be built.
You should also be able to confirm this by looking at the nvcc compile command line generated for euler3d (which you don't show) and comparing it to the one for euler3d_double (which is failing).

undefined reference to symbol 'cudaStreamCreate'

Building my project using CMake I get the following linker error and don't know how to solve it. Using make VERBOSE=1 reveals the generated commands which look ok to me:
azg#HPC:~/code/myproject/build_debug$ /usr/bin/c++ -Wall -Wextra -Wshadow -Woverloaded
-virtual -g3 -ggdb3 -fopenmp CMakeFiles/mymain.dir/main/cpp
/algorithm/mymain.cc.o -o mymain -rdynamic
my_library.a /opt/dev/boost/lib/libboost_filesystem.a /opt/dev/boost
/lib/libboost_graph.a /opt/dev/boost/lib/libboost_system.a /opt/dev/boost
/lib/libboost_program_options.a /opt/dev/boost/lib/libboost_chrono.a /usr/local
/hdf5/lib/libhdf5.so -lz -lrt -ldl -lm /usr/local/cuda-5.0/lib64/libcudart.so -lcuda
/usr/local/cuda-5.0/lib64/libcublas.so /opt/dev/magma/1.4.0-beta2/lib/libmagma.a
/opt/intel/lib/intel64/libimf.so -Wl,-rpath,/usr/local/hdf5/lib:/usr/local/cuda-
5.0/lib64:/opt/intel/lib/intel64/usr/bin/ld:/usr/local/cuda-5.0/lib64/libcublas.so:
and the linker error:
undefined reference to symbol 'cudaStreamCreate'
/usr/bin/ld: note: 'cudaStreamCreate' is defined in DSO /usr/local/cuda-5.0/lib64/libcudart.so so try adding it to the linker command line
/usr/local/cuda-5.0/lib64/libcudart.so: could not read symbols: Invalid operation
collect2: ld returned 1 exit status
The linker error message is telling you exactly what to do to fix this.
Don't specify shared libraries as files, that passes them to the compiler which ignores them. Pass each library search path to the linker with -L and each library stub name with -l. The linker will search for a suitable version of the library (either shared or static depending on what therer is available and the build options you pass) and then link the full list of dependencies together. The resulting build command might look like:
c++ -Wall -Wextra -Wshadow -Woverloaded \
-virtual -g3 -ggdb3 -fopenmp CMakeFiles/mymain.dir/main/cpp \
/algorithm/mymain.cc.o -o mymain -rdynamic my_library.a \
-L/opt/dev/boost/lib \
-L/usr/local/hdf5/lib \
-L/usr/local/cuda-5.0/lib64 \
-L/opt/dev/magma/1.4.0-beta2/lib \
-L/opt/intel/lib/intel64 \
-lboost_filesystem \
-lboost_graph \
-lboost_system \
-lboost_program_options \
-lboost_chrono \
-lhdf5 \
-lz -lrt -ldl -lm \
-lcudart \
-lcuda \
-lcublas \
-lmagma \
-limf
-Wl,-rpath,/usr/local/hdf5/lib:/usr/local/cuda- 5.0/lib64:/opt/intel/lib/intel64/usr/bin/ld
[huge disclaimer: cut and pasted on an ipad on the end of a very flaky GSM connection in the middle of lapland. Not expected to actually work]
I have no idea how you get Cmake to do that, and you haven't shown us a Makefile so that is about as much help as I can offer.