nvcc fatal : A single input file is required for a non-link phase (Due to Reallocated device code)

I got the above error when i try to build my project which contains relocatable device code.

Till-now, when i use the device code in one file i.e. kernel.cu, building went just fine. Now i had a function which is used by both the device and host, so i modified that function with a prefix host device and passed -dc flag to nvcc.

When i tried building the project using Cmake/make, it shows the following

/usr/local/bin/cmake -E cmake_link_script CMakeFiles/test_zip1_gpu.dir/dlink.txt --verbose=1
/usr/bin/nvcc   -arch=sm_50 --ptxas-options=-v -Xptxas -dlcm=ca -dc -Xcompiler=-fPIC  -shared -dlink CMakeFiles/test_zip1_gpu.dir/src/kernel.cu.o CMakeFiles/test_zip1_gpu.dir/src/main.cu.o CMakeFiles/test_zip1_gpu.dir/src/adler32.c.o CMakeFiles/test_zip1_gpu.dir/src/END_OF_CENTRAL_DIR.cu.o CMakeFiles/test_zip1_gpu.dir/src/CENTRAL_DIR.cu.o CMakeFiles/test_zip1_gpu.dir/src/LOCAL_FILE_HEADER.cu.o CMakeFiles/test_zip1_gpu.dir/src/ENCRYPTION_HEADER.cu.o CMakeFiles/test_zip1_gpu.dir/src/DATA_DESCRIPTOR.cu.o CMakeFiles/test_zip1_gpu.dir/src/MEMORY_FREE_AVAILABLE.cu.o CMakeFiles/test_zip1_gpu.dir/src/EXTRACT_DATA_BYTES.cu.o CMakeFiles/test_zip1_gpu.dir/src/crc32_checksum.cu.o CMakeFiles/test_zip1_gpu.dir/src/AES_STRUCTURE.cu.o CMakeFiles/test_zip1_gpu.dir/src/aes_modes.c.o CMakeFiles/test_zip1_gpu.dir/src/aescrypt.c.o CMakeFiles/test_zip1_gpu.dir/src/aeskey.c.o CMakeFiles/test_zip1_gpu.dir/src/aestab.c.o CMakeFiles/test_zip1_gpu.dir/src/aes_ni.c.o CMakeFiles/test_zip1_gpu.dir/src/pwd2key.c.o CMakeFiles/test_zip1_gpu.dir/src/hmac.c.o CMakeFiles/test_zip1_gpu.dir/src/sha1.c.o CMakeFiles/test_zip1_gpu.dir/src/sha2.c.o CMakeFiles/test_zip1_gpu.dir/src/fileenc.c.o CMakeFiles/test_zip1_gpu.dir/src/DECRYPTION.cu.o -o CMakeFiles/test_zip1_gpu.dir/cmake_device_link.o -Xnvlink libz.so.1.2.11  -L"/usr/lib/x86_64-linux-gnu"
nvcc fatal   : A single input file is required for a non-link phase when an outputfile is specified
CMakeFiles/test_zip1_gpu.dir/build.make:414: recipe for target 'CMakeFiles/test_zip1_gpu.dir/cmake_device_link.o' failed

I would like to paste the cmake file here for more info

cmake_minimum_required(VERSION 3.8)

project(test_zip1_gpu LANGUAGES CUDA C)
option(ASM686 "Enable building i686 assembly implementation")
option(AMD64 "Enable building amd64 assembly implementation")

#CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-9.2/


set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for include")
set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages")
set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files")

include(CheckTypeSize)
include(CheckFunctionExists)
include(CheckIncludeFile)
include(CheckCSourceCompiles)
enable_testing()

check_include_file(sys/types.h HAVE_SYS_TYPES_H)
check_include_file(stdint.h    HAVE_STDINT_H)
check_include_file(stddef.h    HAVE_STDDEF_H)

#
# Check to see if we have large file support
#
set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1)
# We add these other definitions here because CheckTypeSize.cmake
# in CMake 2.4.x does not automatically do so and we want
# compatibility with CMake 2.4.x.
if(HAVE_SYS_TYPES_H)
    list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H)
endif()
if(HAVE_STDINT_H)
    list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H)
endif()
if(HAVE_STDDEF_H)
    list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H)
endif()
check_type_size(off64_t OFF64_T)
if(HAVE_OFF64_T)
   add_definitions(-D_LARGEFILE64_SOURCE=1)
endif()
set(CMAKE_REQUIRED_DEFINITIONS) # clear variable

#
# Check for fseeko
#
check_function_exists(fseeko HAVE_FSEEKO)
if(NOT HAVE_FSEEKO)
    add_definitions(-DNO_FSEEKO)
endif()

#
# Check for unistd.h
#
check_include_file(unistd.h Z_HAVE_UNISTD_H)

if(MSVC)
    set(CMAKE_DEBUG_POSTFIX "d")
    add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
    add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
    include_directories(${CMAKE_CURRENT_SOURCE_DIR})
endif()

if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
    # If we're doing an out of source build and the user has a zconf.h
    # in their source tree...
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h)
        message(STATUS "Renaming")
        message(STATUS "    ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h")
        message(STATUS "to 'zconf.h.included' because this file is included with zlib")
        message(STATUS "but CMake generates it automatically in the build directory.")
        file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.included)
  endif()
endif()

set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc)
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein
		${ZLIB_PC} @ONLY)
configure_file(	${CMAKE_CURRENT_SOURCE_DIR}/include/zconf.h.cmakein
		${CMAKE_CURRENT_BINARY_DIR}/include/zconf.h @ONLY)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR})


#============================================================================
# zlib
#============================================================================

set(ZLIB_PUBLIC_HDRS
    ${CMAKE_CURRENT_BINARY_DIR}/include/zconf.h
    ${CMAKE_CURRENT_SOURCE_DIR}/include/zlib.h
)
set(ZLIB_PRIVATE_HDRS
    ${CMAKE_CURRENT_SOURCE_DIR}/include/crc32.h
    ${CMAKE_CURRENT_SOURCE_DIR}/include/deflate.h
    ${CMAKE_CURRENT_SOURCE_DIR}/include/gzguts.h
    ${CMAKE_CURRENT_SOURCE_DIR}/include/inffast.h
    ${CMAKE_CURRENT_SOURCE_DIR}/include/inffixed.h
    ${CMAKE_CURRENT_SOURCE_DIR}/include/inflate.h
    ${CMAKE_CURRENT_SOURCE_DIR}/include/inftrees.h
    ${CMAKE_CURRENT_SOURCE_DIR}/include/trees.h
    ${CMAKE_CURRENT_SOURCE_DIR}/include/zutil.h
)
set(ZLIB_SRCS
    ${CMAKE_CURRENT_SOURCE_DIR}/src/adler32.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/compress.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/crc32.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/deflate.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/gzclose.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/gzlib.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/gzread.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/gzwrite.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/inflate.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/infback.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/inftrees.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/inffast.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/trees.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/uncompr.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/zutil.c
)

if(NOT MINGW)
    set(ZLIB_DLL_SRCS
        win32/zlib1.rc # If present will override custom build rule below.
    )
endif()

if(CMAKE_COMPILER_IS_GNUCC)
    if(ASM686)
        set(ZLIB_ASMS contrib/asm686/match.S)
    elseif (AMD64)
        set(ZLIB_ASMS contrib/amd64/amd64-match.S)
    endif ()

	if(ZLIB_ASMS)
		add_definitions(-DASMV)
		set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE)
	endif()
endif()

if(MSVC)
    if(ASM686)
		ENABLE_LANGUAGE(ASM_MASM)
        set(ZLIB_ASMS
			contrib/masmx86/inffas32.asm
			contrib/masmx86/match686.asm
		)
    elseif (AMD64)
		ENABLE_LANGUAGE(ASM_MASM)
        set(ZLIB_ASMS
			contrib/masmx64/gvmat64.asm
			contrib/masmx64/inffasx64.asm
		)
    endif()

	if(ZLIB_ASMS)
		add_definitions(-DASMV -DASMINF)
	endif()
endif()

# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION
file(READ include/zlib.h _zlib_h_contents)
string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*"
    "\1" ZLIB_FULL_VERSION ${_zlib_h_contents})

if(MINGW)
    # This gets us DLL resource information when compiling on MinGW.
    if(NOT CMAKE_RC_COMPILER)
        set(CMAKE_RC_COMPILER windres.exe)
    endif()

    add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj
                       COMMAND ${CMAKE_RC_COMPILER}
                            -D GCC_WINDRES
                            -I ${CMAKE_CURRENT_SOURCE_DIR}
                            -I ${CMAKE_CURRENT_BINARY_DIR}
                            -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj
                            -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc)
    set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj)
endif(MINGW)

add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL)
set_target_properties(zlib PROPERTIES SOVERSION 1)

if(NOT CYGWIN)
    # This property causes shared libraries on Linux to have the full version
    # encoded into their final filename.  We disable this on Cygwin because
    # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll
    # seems to be the default.
    #
    # This has no effect with MSVC, on that platform the version info for
    # the DLL comes from the resource file win32/zlib1.rc
    set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION})
endif()

if(UNIX)
    # On unix-like platforms the library is almost always called libz
   set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z)
   if(NOT APPLE)
     set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"")
   endif()
elseif(BUILD_SHARED_LIBS AND WIN32)
    # Creates zlib1.dll when building shared library version
    set_target_properties(zlib PROPERTIES SUFFIX "1.dll")
endif()

if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL )
    install(TARGETS zlib zlibstatic
        RUNTIME DESTINATION "${INSTALL_BIN_DIR}"
        ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
        LIBRARY DESTINATION "${INSTALL_LIB_DIR}" )
endif()
if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL )
    install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION "${INSTALL_INC_DIR}")
endif()
if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL )
    install(FILES zlib.3 DESTINATION "${INSTALL_MAN_DIR}/man3")
endif()
if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL )
    install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}")
endif()


#============================================================================
# Example binaries
#============================================================================

add_executable(test_zip1_gpu src/kernel.cu src/main.cu src/adler32.c src/END_OF_CENTRAL_DIR.cu src/CENTRAL_DIR.cu src/LOCAL_FILE_HEADER.cu src/ENCRYPTION_HEADER.cu src/DATA_DESCRIPTOR.cu src/MEMORY_FREE_AVAILABLE.cu src/EXTRACT_DATA_BYTES.cu src/crc32_checksum.cu src/AES_STRUCTURE.cu src/aes_modes.c src/aescrypt.c src/aeskey.c src/aestab.c src/aes_ni.c src/pwd2key.c src/hmac.c src/sha1.c src/sha2.c src/fileenc.c src/DECRYPTION.cu)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -arch=sm_50 --ptxas-options=-v -Xptxas -dlcm=ca")
target_link_libraries(test_zip1_gpu zlib)
install(TARGETS test_zip1_gpu RUNTIME DESTINATION bin)

The fact that a function is decorated with host device does not, by itself, necessitate the use of device linking. If any function decorated with device is defined in one compilation unit but used (in device code) in another compilation unit, then device linking is required.

It would probably help if you indicated how you “passed -dc flag to nvcc”. It’s not evident from your Cmake file (is it?)

In any event, the command being generated by cmake is mal-formed:

/usr/bin/nvcc   -arch=sm_50 --ptxas-options=-v -Xptxas -dlcm=ca -dc -Xcompiler=-fPIC  -shared -dlink CMakeFiles/test_zip1_gpu.dir/src/kernel.cu.o CMakeFiles/test_zip1_gpu.dir/src/main.cu.o CMakeFiles/test_zip1_gpu.dir/src/adler32.c.o CMakeFiles/test_zip1_gpu.dir/src/END_OF_CENTRAL_DIR.cu.o CMakeFiles/test_zip1_gpu.dir/src/CENTRAL_DIR.cu.o CMakeFiles/test_zip1_gpu.dir/src/LOCAL_FILE_HEADER.cu.o CMakeFiles/test_zip1_gpu.dir/src/ENCRYPTION_HEADER.cu.o CMakeFiles/test_zip1_gpu.dir/src/DATA_DESCRIPTOR.cu.o CMakeFiles/test_zip1_gpu.dir/src/MEMORY_FREE_AVAILABLE.cu.o CMakeFiles/test_zip1_gpu.dir/src/EXTRACT_DATA_BYTES.cu.o CMakeFiles/test_zip1_gpu.dir/src/crc32_checksum.cu.o CMakeFiles/test_zip1_gpu.dir/src/AES_STRUCTURE.cu.o CMakeFiles/test_zip1_gpu.dir/src/aes_modes.c.o CMakeFiles/test_zip1_gpu.dir/src/aescrypt.c.o CMakeFiles/test_zip1_gpu.dir/src/aeskey.c.o CMakeFiles/test_zip1_gpu.dir/src/aestab.c.o CMakeFiles/test_zip1_gpu.dir/src/aes_ni.c.o CMakeFiles/test_zip1_gpu.dir/src/pwd2key.c.o CMakeFiles/test_zip1_gpu.dir/src/hmac.c.o CMakeFiles/test_zip1_gpu.dir/src/sha1.c.o CMakeFiles/test_zip1_gpu.dir/src/sha2.c.o CMakeFiles/test_zip1_gpu.dir/src/fileenc.c.o CMakeFiles/test_zip1_gpu.dir/src/DECRYPTION.cu.o -o CMakeFiles/test_zip1_gpu.dir/cmake_device_link.o -Xnvlink libz.so.1.2.11  -L"/usr/lib/x86_64-linux-gnu"

-dc indicates a device-compile step. It expects to receive ordinary source files (e.g. .cu) If the compile command that includes -dc also includes -o (as this one does) then it can only accept one such source file.

This command does not fit that pattern, as all the files passed to it are already compiled objects (and there are multiple of those, with a -o specification, which is the proximal reason for the error).

My guess is that you have decided to insert -dc where it does not belong in one of your scripts. The command presented is an otherwise properly formed device-link step/phase, and recent versions of Cmake know already how to do this, without you including -dc somewhere that it doesn’t belong.

I had inserted the -dc flag in the cmake file, like this one

set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -arch=sm_50 --ptxas-options=-v -Xptxas -dlcm=ca -dc")

If i don’t pass the -dc flag like above, the make generate “Unresolved Extern” for the host device function, like below for the CRC32 function

/usr/bin/nvcc  -D_LARGEFILE64_SOURCE=1 -I/home/nomi/cuda-workspace/test_zip1_gpu  -arch=sm_50 --ptxas-options=-v -Xptxas -dlcm=ca   -x cu -c /home/nomi/cuda-workspace/test_zip1_gpu/src/kernel.cu -o CMakeFiles/test_zip1_gpu.dir/src/kernel.cu.o
ptxas fatal   : Unresolved extern function '_Z9CRC32_NEWjh'
CMakeFiles/test_zip1_gpu.dir/build.make:62: recipe for target 'CMakeFiles/test_zip1_gpu.dir/src/kernel.cu.o' failed

Update: I tried compiling the individual kernel.cu which calls the CRC function in crc32_new.cu. It compiles just fine.

nvcc -c -dc kernel.cu -I../

But without the -dc flag, it reports Extern error

$  nvcc -c kernel.cu -I../

   ptxas fatal   : Unresolved extern function '_Z9CRC32_NEWjh'

And you are right about -dc flag that it does accept only source files, but i’m not able to track why objects files are passed to it in my case. I am definitely doing something wrong in the cmake file.

The issue is resolved by adding the below property.

set_property(TARGET MyProg PROPERTY CUDA_SEPARABLE_COMPILATION ON)

The make output when i used the above set_property(…) is the following

/usr/bin/nvcc  -D_LARGEFILE64_SOURCE=1 -I/home/nomi/cuda-workspace/test_zip1_gpu  --ptxas-options=-v -Xptxas -dlcm=ca   -x cu -dc /home/nomi/cuda-workspace/test_zip1_gpu/src/kernel.cu -o CMakeFiles/test_zip1_gpu.dir/src/kernel.cu.o

Problem solved.