aboutsummaryrefslogtreecommitdiffhomepage
path: root/CMake/GeneratePkgConfig.cmake
blob: cd05568c69b04bfbf4721acb9f4adc5d488bfbe3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
function(get_relative_link OUTPUT PATH)
  if (PATH MATCHES "^[$]<[$]<CONFIG:DEBUG>:")
    set(${OUTPUT} "" PARENT_SCOPE)
    return()
  endif()
  string(REGEX REPLACE "^[$]<[$]<NOT:[$]<CONFIG:DEBUG>>:(.*)>$" "\\1" PATH "${PATH}")

  get_filename_component(NAME "${PATH}" NAME_WE)
  if (IS_ABSOLUTE ${PATH})
    get_filename_component(DIRECTORY_NAME "${PATH}" DIRECTORY)
    if (WIN32)
      # On Windows, library files can be libname.lib or name.lib
      get_filename_component(FULL_NAME "${PATH}" NAME)
      # Extract library name without lib prefix and extension
      string(REGEX REPLACE "^lib(.+)\\.[^.]+$" "\\1" LIB_NAME "${FULL_NAME}")
      # If the regex didn't match (no lib prefix), use the name without extension
      if ("${LIB_NAME}" STREQUAL "${FULL_NAME}")
        set(LIB_NAME "${NAME}")
      endif()
      set(${OUTPUT} "-L\"${DIRECTORY_NAME}\" -l${LIB_NAME}" PARENT_SCOPE)
    else()
      get_filename_component(FULL_NAME "${PATH}" NAME)
      # Extract library name without lib prefix and extension for all platforms
      string(REGEX REPLACE "^lib(.+)\\.[^.]+$" "\\1" LIB_NAME "${FULL_NAME}")
      set(${OUTPUT} "-L\"${DIRECTORY_NAME}\" -l${LIB_NAME}" PARENT_SCOPE)
    endif()
    return()
  endif()

  if (NOT WIN32 AND NAME MATCHES "^lib")
    string(REGEX REPLACE "^lib" "-l" LINK "${NAME}")
  elseif (NAME MATCHES "^-")
    set(LINK "${NAME}")
  else()
    string(CONCAT LINK "-l" "${NAME}")
  endif()
  set(${OUTPUT} "${LINK}" PARENT_SCOPE)
endfunction()

function(generate_pkgconfig TARGET DESCRIPTION)
  # message("Generating pkg-config for ${TARGET}")
  get_filename_component(PREFIX "${CMAKE_INSTALL_PREFIX}" REALPATH)

  # Get the target type to handle interface libraries differently
  get_target_property(LIBRARY_TYPE "${TARGET}" TYPE)
  # For interface libraries, use INTERFACE_LINK_LIBRARIES instead of LINK_LIBRARIES
  if ("${LIBRARY_TYPE}" STREQUAL "INTERFACE_LIBRARY")
    get_target_property(LIST "${TARGET}" INTERFACE_LINK_LIBRARIES)
  else()
    get_target_property(LIST "${TARGET}" LINK_LIBRARIES)
  endif()

  # Handle the case when no libraries are found
  if ("${LIST}" STREQUAL "LIST-NOTFOUND")
    set(LIST "")
  endif()

  # Special handling for tdcore interface library
  if ("${TARGET}" STREQUAL "tdcore" AND "${LIBRARY_TYPE}" STREQUAL "INTERFACE_LIBRARY")
    # For tdcore interface library, we need to link to the actual part libraries
    # instead of the non-existent tdcore library
    set(TDCORE_LIBS "")
    set(COMBINED_REQS "")
    set(COMBINED_LIBS "")
    
    foreach (PART_LIB ${LIST})
      if (TARGET "${PART_LIB}" AND "${PART_LIB}" MATCHES "^tdcore_part[0-9]+$")
        # Add the actual part library to link against
        list(APPEND TDCORE_LIBS "-l${PART_LIB}")
        
        # Collect dependencies from the parts
        get_target_property(PART_LIST "${PART_LIB}" LINK_LIBRARIES)
        if (NOT "${PART_LIST}" STREQUAL "PART_LIST-NOTFOUND")
          foreach (PART_DEP ${PART_LIST})
            if (TARGET "${PART_DEP}")
              list(APPEND COMBINED_REQS "${PART_DEP}")
            else()
              list(APPEND COMBINED_LIBS "${PART_DEP}")
            endif()
          endforeach()
        endif()
      elseif (TARGET "${PART_LIB}")
        list(APPEND COMBINED_REQS "${PART_LIB}")
      else()
        list(APPEND COMBINED_LIBS "${PART_LIB}")
      endif()
    endforeach()

    # Remove duplicates
    if (COMBINED_REQS)
      list(REMOVE_DUPLICATES COMBINED_REQS)
    endif()
    if (COMBINED_LIBS)
      list(REMOVE_DUPLICATES COMBINED_LIBS)
    endif()
    if (TDCORE_LIBS)
      list(REMOVE_DUPLICATES TDCORE_LIBS)
    endif()

    set(LIST "")
    list(APPEND LIST ${COMBINED_REQS})
    list(APPEND LIST ${COMBINED_LIBS})

    # Set a flag to use different Libs line for tdcore
    set(USE_TDCORE_PARTS TRUE)
  else()
    set(USE_TDCORE_PARTS FALSE)
  endif()

  set(REQS "")
  set(LIBS "")
  foreach (LIB ${LIST})
    if (TARGET "${LIB}")
      # Skip internal tdcore parts as they don't have their own .pc files
      if (NOT "${LIB}" MATCHES "^tdcore_part[0-9]+$")
        set(HAS_REQS 1)
        list(APPEND REQS "${LIB}")
      endif()
    else()
      set(HAS_LIBS 1)
      get_relative_link(LINK "${LIB}")
      if (NOT "${LINK}" STREQUAL "")
        list(APPEND LIBS "${LINK}")
      endif()
    endif()
  endforeach()

  if (HAS_REQS)
    set(REQUIRES "")
    foreach (REQ ${REQS})
      set(REQUIRES "${REQUIRES} ${REQ}")
    endforeach()
    set(REQUIRES "Requires.private:${REQUIRES}\n")
  endif()
  if (HAS_LIBS)
    set(LIBRARIES "")
    list(REVERSE LIBS)
    list(REMOVE_DUPLICATES LIBS)
    foreach (LIB ${LIBS})
      set(LIBRARIES " ${LIB}${LIBRARIES}")
    endforeach()
    set(LIBRARIES "Libs.private:${LIBRARIES}\n")
  endif()

  if (IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
    set(PKGCONFIG_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
  else()
    set(PKGCONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
  endif()

  if (IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
    set(PKGCONFIG_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
  else()
    set(PKGCONFIG_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
  endif()

  file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig")
  
  # Generate the correct Libs line based on library type
  if (USE_TDCORE_PARTS)
    # For tdcore interface library, link to the actual part libraries
    set(LIBS_LINE "")
    foreach (PART_LIB ${TDCORE_LIBS})
      set(LIBS_LINE "${LIBS_LINE} ${PART_LIB}")
    endforeach()
    set(LIBS_LINE "Libs: -L\"${PKGCONFIG_LIBDIR}\"${LIBS_LINE}")
  else()
    set(LIBS_LINE "Libs: -L\"${PKGCONFIG_LIBDIR}\" -l${TARGET}")
  endif()
  
  file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/${TARGET}.pc" CONTENT
"prefix=${PREFIX}

Name: ${TARGET}
Description: ${DESCRIPTION}
Version: ${PROJECT_VERSION}

CFlags: -I\"${PKGCONFIG_INCLUDEDIR}\"
${LIBS_LINE}
${REQUIRES}${LIBRARIES}")

  if ("${LIBRARY_TYPE}" STREQUAL "STATIC_LIBRARY" OR "${LIBRARY_TYPE}" STREQUAL "SHARED_LIBRARY")
    install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/${TARGET}.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
  elseif ("${LIBRARY_TYPE}" STREQUAL "INTERFACE_LIBRARY")
    # Interface libraries are also supported, install the .pc file
    install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/${TARGET}.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
  else()
    message(FATAL_ERROR "Don't know how to handle ${TARGET} of type ${LIBRARY_TYPE}")
  endif()
endfunction()