সিএমকে: বাহ্যিক প্রকল্পগুলি কীভাবে তৈরি করা যায় এবং তাদের লক্ষ্যগুলি অন্তর্ভুক্ত করা যায়


113

আমার একটি প্রকল্প আছে যা লক্ষ্য হিসাবে একটি স্ট্যাটিক লাইব্রেরি রফতানি করে:

install(TARGETS alib DESTINATION lib EXPORT project_a-targets)
install(EXPORT project_a-targets DESTINATION lib/alib)

এখন আমি প্রকল্প এ থেকে প্রকল্প এটিকে একটি বাহ্যিক প্রকল্প হিসাবে ব্যবহার করতে চাই এবং এর নির্মিত লক্ষ্যগুলি অন্তর্ভুক্ত করব:

ExternalProject_Add(project_a
  URL ...project_a.tar.gz
  PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a
  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
)

include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake)

সমস্যাটি হ'ল প্রকল্প বিয়ের সিএমকেলিস্টগুলি চলাকালীন অন্তর্ভুক্ত ফাইলটি এখনও বিদ্যমান নেই।

বাহ্যিক প্রকল্প নির্মিত হচ্ছে এর উপর নির্ভরশীল করার কোনও উপায় আছে কি?

আপডেট : আমিএই এবং অন্যান্য সাধারণ সমস্যার মুখোমুখি আমি উদাহরণ টিউটোরিয়াল দ্বারা একটি সংক্ষিপ্ত সিএমকে লিখেছি।

উত্তর:


67

আমি মনে করি আপনি এখানে দুটি পৃথক দৃষ্টান্ত মিশ্রিত করছেন।

যেমনটি আপনি উল্লেখ করেছেন, অত্যন্ত নমনীয় ExternalProjectমডিউলটি তার সময় কমান্ডগুলি চালিত করে, তাই আপনি প্রকল্প এ এর ​​আমদানি ফাইলটির সরাসরি ব্যবহার করতে পারবেন না কারণ এটি কেবলমাত্র প্রকল্প এ ইনস্টল হওয়ার পরে তৈরি করা হয়েছে।

যদি আপনি চাই প্রতি includeপ্রকল্প ক-এর আমদানি ফাইল, আপনি করব আছে ম্যানুয়ালি প্রকল্প খ এর CMakeLists.txt invoking আগে প্রকল্পটি একটি ইনস্টল করতে - অন্য কোন তৃতীয় পক্ষের নির্ভরতা ঠিক এই ভাবে যোগ করা বা মাধ্যমে find_file/ find_library/ find_package

আপনি যদি এটি ব্যবহার ExternalProject_Addকরতে চান তবে আপনাকে নিজের সিএমকেলিস্টস টেক্সটে নিম্নলিখিত জাতীয় কিছু যুক্ত করতে হবে:

ExternalProject_Add(project_a
  URL ...project_a.tar.gz
  PREFIX ${CMAKE_CURRENT_BINARY_DIR}/project_a
  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
)

include(${CMAKE_CURRENT_BINARY_DIR}/lib/project_a/project_a-targets.cmake)

ExternalProject_Get_Property(project_a install_dir)
include_directories(${install_dir}/include)

add_dependencies(project_b_exe project_a)
target_link_libraries(project_b_exe ${install_dir}/lib/alib.lib)

2
আপনার উত্তরের জন্য ধন্যবাদ. আপনি যা পরামর্শ দেন তা আমার আগে যা ছিল তার অনুরূপ। আমি রফতানি করা লক্ষ্যগুলি ব্যবহার করার একটি উপায় খুঁজে প্রত্যাশা করলাম কারণ এটি
স্বতঃপ্রণোদিত হয়ে

7
আমি আমার উত্স ট্রিতে বাহ্যিক প্রকল্পগুলির উত্স অন্তর্ভুক্ত করা এড়াতে চেয়েছিলাম। এটি ExternalProject_Addকেবল দুর্দান্ত আচরণের মতো add_subdirectoryএবং সমস্ত লক্ষ্যগুলি উন্মোচিত করলে দুর্দান্ত হবে। আপনি উপরে বর্ণিত সমাধান সম্ভবত এখনও সবচেয়ে পরিষ্কার।
মিরকোকিফার

2
এগুলি উভয়ই বহির্মুখী প্রকল্পের বিল্ডিংয়ের কথা বিবেচনা করুন, এবং তারপরে বি এ এর ​​উপর নির্ভরশীল থাকুন এবং তারপরে প্রকল্প বিয়ের জন্য সিএমকেলিস্ট ফাইলগুলিতে প্রকল্প এ থেকে লক্ষ্যগুলি ফাইল অন্তর্ভুক্ত করা হবে, তবে আপনার "সুপার বিল্ড" সিএমকেলিস্টগুলি কেবল একটি এবং তারপরে বি নির্মাণ করবে, উভয়ই বহিরাগত প্রকল্প হিসাবে ...
ডিএলআরডেভ

3
@ ডিএলআরডেভ - আমি সুপার বিল সলিউশনটি কয়েকবার প্রস্তাবিত দেখেছি, তবে আমার ধারণা আমি নিশ্চিত না যে এটির মাধ্যমে কেবলমাত্র কয়েকটি বাহ্যিক প্রকল্প সহ কী কী উপকার হয় ExternalProject। এটি কি ধারাবাহিকতা, বা আরও প্রচলিত, বা অন্য কিছু? আমি নিশ্চিত যে আমি এখানে মৌলিক কিছু মিস করছি।
ফ্রেজার

6
এই সমাধানটির অন্যতম সমস্যা হ'ল আমরা কেবল লাইব্রেরির নাম (alib.lib) হার্ডকোড করেছি, যা বিল্ড সিস্টেমকে ক্রস-প্ল্যাটফর্ম হিসাবে না করে তোলে, কারণ বিভিন্ন ওএস ভাগ করা লাইব্রেরিগুলির জন্য বিভিন্ন নামকরণের স্কিম ব্যবহার করে এবং এই বিভিন্ন নামকরণের সাথে খাপ খাইয়ে নেয় স্কিমগুলি সিএমকেকের অন্যতম বৈশিষ্ট্য।
এনএসজি

22

এই পোস্টের একটি যুক্তিসঙ্গত উত্তর আছে:

CMakeLists.txt.in:

cmake_minimum_required(VERSION 2.8.2)

project(googletest-download NONE)

include(ExternalProject)
ExternalProject_Add(googletest
  GIT_REPOSITORY    https://github.com/google/googletest.git
  GIT_TAG           master
  SOURCE_DIR        "${CMAKE_BINARY_DIR}/googletest-src"
  BINARY_DIR        "${CMAKE_BINARY_DIR}/googletest-build"
  CONFIGURE_COMMAND ""
  BUILD_COMMAND     ""
  INSTALL_COMMAND   ""
  TEST_COMMAND      ""
)

CMakeLists.txt:

# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in
               googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
execute_process(COMMAND ${CMAKE_COMMAND} --build .
  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )

# Prevent GoogleTest from overriding our compiler/linker options
# when building with Visual Studio
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)

# Add googletest directly to our build. This adds
# the following targets: gtest, gtest_main, gmock
# and gmock_main
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
                 ${CMAKE_BINARY_DIR}/googletest-build)

# The gtest/gmock targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later. Otherwise we have to add them here ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
  include_directories("${gtest_SOURCE_DIR}/include"
                      "${gmock_SOURCE_DIR}/include")
endif()

# Now simply link your own targets against gtest, gmock,
# etc. as appropriate

তবে এটি বেশ কড়া মনে হয়। আমি একটি বিকল্প সমাধান প্রস্তাব করতে চাই - গিট সাবমডিউলগুলি ব্যবহার করুন।

cd MyProject/dependencies/gtest
git submodule add https://github.com/google/googletest.git
cd googletest
git checkout release-1.8.0
cd ../../..
git add *
git commit -m "Add googletest"

তারপরে আপনি এর MyProject/dependencies/gtest/CMakeList.txtমতো কিছু করতে পারেন:

cmake_minimum_required(VERSION 3.3)

if(TARGET gtest) # To avoid diamond dependencies; may not be necessary depending on you project.
    return()
endif()

add_subdirectory("googletest")

আমি এখনও এটি ব্যাপকভাবে চেষ্টা করে দেখিনি তবে এটি আরও পরিষ্কার বলে মনে হচ্ছে।

সম্পাদনা করুন: এই পদ্ধতির একটি খারাপ দিক রয়েছে: উপ-ডিরেক্টরিটি install()আপনি চান না এমন আদেশগুলি চালাতে পারে । এই পোস্টটি তাদের অক্ষম করার জন্য একটি পদ্ধতির রয়েছে তবে এটি বাগি ছিল এবং আমার পক্ষে কাজ করে নি।

সম্পাদনা 2: আপনি যদি add_subdirectory("googletest" EXCLUDE_FROM_ALL)এটি ব্যবহার করেন বলে মনে হয় এর অর্থ install()উপ-ডিরেক্টরিতে কমান্ডগুলি ডিফল্টরূপে ব্যবহৃত হয় না।


এটি সম্ভবত আমি মাত্রাতিরিক্ত সতর্ক থাকি কারণ এটি কেবল একটি উদাহরণ এবং গেষ্টটি সম্ভবত বেশ স্থিতিশীল, তবে আমি দৃ strongly়তার সাথে সবসময় GIT_TAGক্লোন চলাকালীন একটি নির্দিষ্ট ব্যবহারের পরামর্শ দিই , আপনি বিল্ড রিপিটিবিলিটি হারাতে পারেন কারণ এখন থেকে বিল্ড স্ক্রিপ্টটি চালানো কেউ একজন পাবেন a আপনি যা করেছেন তার চেয়ে আলাদা সংস্করণ। CMake এর ডক্স খুব এই সুপারিশ।
16

5

সম্পাদনা করুন: সিএমকে এখন এটির জন্য সমর্থন তৈরি করেছে। নতুন উত্তর দেখুন ।

আপনি কোনও মাধ্যমিক তৈরির প্রক্রিয়াতে নির্ভরশীল লক্ষ্য তৈরি করতে বাধ্য করতে পারেন

সম্পর্কিত বিষয়ে আমার উত্তর দেখুন ।


1

চটজলদি ExternalProject_Addপ্রকৃতপক্ষে ব্যবহার করতে পারে তবে আমি এটি সম্পর্কে যা পছন্দ করি না তা হ'ল এটি বিল্ড, ক্রমাগত পোল ইত্যাদির সময় কিছু সম্পাদন করে ... আমি বিল্ড ফেজ চলাকালীন প্রকল্পটি বানাতে পছন্দ করব, অন্য কিছু নয়। ExternalProject_Addদুর্ভাগ্যক্রমে সফলতা ছাড়াই আমি বেশ কয়েকটি প্রয়াসে ওভাররাইড করার চেষ্টা করেছি ।

তারপরে আমি গিট সাবমোডুল যুক্ত করার চেষ্টাও করেছি, তবে এটি পুরো গিট সংগ্রহস্থলকে টেনে নিয়ে যায়, যখন কিছু ক্ষেত্রে আমার পুরো গিট সংগ্রহস্থলের কেবলমাত্র সাবসেট প্রয়োজন। আমি যা যা দেখেছি - স্পার্স গিট চেকআউট সম্পাদন করা সত্যিই সম্ভব, তবে এর জন্য পৃথক ফাংশন প্রয়োজন যা আমি নীচে লিখেছি।

#-----------------------------------------------------------------------------
#
# Performs sparse (partial) git checkout
#
#   into ${checkoutDir} from ${url} of ${branch}
#
# List of folders and files to pull can be specified after that.
#-----------------------------------------------------------------------------
function (SparseGitCheckout checkoutDir url branch)
    if(EXISTS ${checkoutDir})
        return()
    endif()

    message("-------------------------------------------------------------------")
    message("sparse git checkout to ${checkoutDir}...")
    message("-------------------------------------------------------------------")

    file(MAKE_DIRECTORY ${checkoutDir})

    set(cmds "git init")
    set(cmds ${cmds} "git remote add -f origin --no-tags -t master ${url}")
    set(cmds ${cmds} "git config core.sparseCheckout true")

    # This command is executed via file WRITE
    # echo <file or folder> >> .git/info/sparse-checkout")

    set(cmds ${cmds} "git pull --depth=1 origin ${branch}")

    # message("In directory: ${checkoutDir}")

    foreach( cmd ${cmds})
        message("- ${cmd}")
        string(REPLACE " " ";" cmdList ${cmd})

        #message("Outfile: ${outFile}")
        #message("Final command: ${cmdList}")

        if(pull IN_LIST cmdList)
            string (REPLACE ";" "\n" FILES "${ARGN}")
            file(WRITE ${checkoutDir}/.git/info/sparse-checkout ${FILES} )
        endif()

        execute_process(
            COMMAND ${cmdList}
            WORKING_DIRECTORY ${checkoutDir}
            RESULT_VARIABLE ret
        )

        if(NOT ret EQUAL "0")
            message("error: previous command failed, see explanation above")
            file(REMOVE_RECURSE ${checkoutDir})
            break()
        endif()
    endforeach()

endfunction()


SparseGitCheckout(${CMAKE_BINARY_DIR}/catch_197 https://github.com/catchorg/Catch2.git v1.9.7 single_include)
SparseGitCheckout(${CMAKE_BINARY_DIR}/catch_master https://github.com/catchorg/Catch2.git master single_include)

কীভাবে এই ফাংশনটি ব্যবহার করবেন তা চিত্রিত করার জন্য আমি নীচে দুটি ফাংশন কল যুক্ত করেছি।

কেউ মাস্টার / ট্রাঙ্ক চেকআউট করতে পছন্দ করতে পারে না কারণ এটি ভেঙে যেতে পারে - তবে নির্দিষ্ট ট্যাগটি নির্দিষ্ট করা সবসময় সম্ভব।

আপনি ক্যাশে ফোল্ডারটি সাফ না করা পর্যন্ত চেকআউট কেবল একবার সম্পাদন করা হবে।


1

আমি অনুরূপ সমাধানের সন্ধান করছিলাম। এখানে উত্তর এবং উপরে টিউটোরিয়াল তথ্যমূলক। আমার সফল সফলতা তৈরি করতে এখানে উল্লেখ করা পোস্ট / ব্লগগুলি অধ্যয়ন করেছি। আমি আমার জন্য সম্পূর্ণ সিএমকেলিস্টস টেক্সট পোস্ট করছি। আমার ধারণা, এটি প্রাথমিকভাবে টেম্পলেট হিসাবে সহায়ক হবে।

"CMakeLists.txt"

cmake_minimum_required(VERSION 3.10.2)

# Target Project
project (ClientProgram)

# Begin: Including Sources and Headers
include_directories(include)
file (GLOB SOURCES "src/*.c")
# End: Including Sources and Headers


# Begin: Generate executables
add_executable (ClientProgram ${SOURCES})
# End: Generate executables


# This Project Depends on External Project(s) 
include (ExternalProject)

# Begin: External Third Party Library
set (libTLS ThirdPartyTlsLibrary)
ExternalProject_Add (${libTLS}
    PREFIX          ${CMAKE_CURRENT_BINARY_DIR}/${libTLS}
# Begin: Download Archive from Web Server
    URL             http://myproject.com/MyLibrary.tgz
    URL_HASH        SHA1=<expected_sha1sum_of_above_tgz_file>
    DOWNLOAD_NO_PROGRESS ON
# End: Download Archive from Web Server

# Begin: Download Source from GIT Repository
#    GIT_REPOSITORY  https://github.com/<project>.git
#    GIT_TAG         <Refer github.com releases -> Tags>
#    GIT_SHALLOW     ON
# End: Download Source from GIT Repository

# Begin: CMAKE Comamnd Argiments
    CMAKE_ARGS      -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/${libTLS}
    CMAKE_ARGS      -DUSE_SHARED_LIBRARY:BOOL=ON
# End: CMAKE Comamnd Argiments    
)

# The above ExternalProject_Add(...) construct wil take care of \
# 1. Downloading sources
# 2. Building Object files
# 3. Install under DCMAKE_INSTALL_PREFIX Directory

# Acquire Installation Directory of 
ExternalProject_Get_Property (${libTLS} install_dir)

# Begin: Importing Headers & Library of Third Party built using ExternalProject_Add(...)
# Include PATH that has headers required by Target Project
include_directories (${install_dir}/include)

# Import librarues from External Project required by Target Project
add_library (lmytls SHARED IMPORTED)
set_target_properties (lmytls PROPERTIES IMPORTED_LOCATION ${install_dir}/lib/libmytls.so)
add_library (lmyxdot509 SHARED IMPORTED)
set_target_properties(lmyxdot509 PROPERTIES IMPORTED_LOCATION ${install_dir}/lib/libmyxdot509.so)

# End: Importing Headers & Library of Third Party built using ExternalProject_Add(...)
# End: External Third Party Library

# Begin: Target Project depends on Third Party Component
add_dependencies(ClientProgram ${libTLS})
# End: Target Project depends on Third Party Component

# Refer libraries added above used by Target Project
target_link_libraries (ClientProgram lmytls lmyxdot509)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.