File Coverage

blib/lib/XS/Install/CMake.pm
Criterion Covered Total %
statement 9 64 14.0
branch 0 14 0.0
condition n/a
subroutine 3 10 30.0
pod 0 3 0.0
total 12 91 13.1


line stmt bran cond sub pod time code
1             package
2             XS::Install::CMake;
3 11     11   76 use strict;
  11         25  
  11         329  
4 11     11   60 use warnings;
  11         22  
  11         478  
5 11     11   10167 use Env qw/@PATH/;
  11         30475  
  11         75  
6              
7             sub configure {
8 0     0 0   my $result = run(@_);
9 0           return import_cmake_properites($result);
10             }
11              
12             sub run {
13 0     0 0   my ($bdir, $props_dir, $target, $options) = @_;
14 0           my $ok = eval { require Alien::cmake3; 1 };
  0            
  0            
15 0 0         die "This module requires Alien::cmake3 to build.\n" unless $ok;
16              
17 0           unshift @PATH, Alien::cmake3->bin_dir;
18 0 0         open(CMAKELISTS, '>', "$props_dir/CMakeLists.txt") or die $!;
19              
20 0           print CMAKELISTS <<'EOS';
21             cmake_minimum_required(VERSION 3.5)
22             project(GetProps)
23              
24             macro(find_package)
25             set(find_package_ARGS ${ARGV})
26             list(REMOVE_ITEM find_package_ARGS "REQUIRED")
27             list(APPEND find_package_ARGS "QUIET")
28             _find_package(${find_package_ARGS})
29             endmacro()
30              
31             if (WIN32)
32             list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .dll)
33             endif()
34              
35             function(is_good_lib_item ret name)
36             set(${ret} FALSE PARENT_SCOPE)
37             if(${name} MATCHES "debug|optimized|general|PRIVATE|PUBLIC|INTERFACE" OR ${name} MATCHES "^-.*" OR TARGET ${name})
38             set(${ret} TRUE PARENT_SCOPE)
39             endif()
40             find_library(${name}_is_good ${name})
41             if(${name}_is_good)
42             set(${ret} TRUE PARENT_SCOPE)
43             endif()
44             endfunction()
45              
46              
47             macro(target_link_libraries)
48             set(TARGET_LINK_LIBS_ARGS ${ARGV})
49             list(REMOVE_AT TARGET_LINK_LIBS_ARGS 0)
50              
51             foreach(ARG ${TARGET_LINK_LIBS_ARGS})
52             is_good_lib_item(is_good ${ARG})
53             message(STATUS "checking " ${ARG} " -> " ${is_good})
54             if(${is_good})
55             list(APPEND TARGET_LINK_LIBS_OK ${ARG})
56             endif()
57             endforeach()
58              
59             if (TARGET_LINK_LIBS_OK)
60             message(STATUS "linking:" ${ARGV0} ${TARGET_LINK_LIBS_OK})
61             _target_link_libraries(${ARGV0} ${TARGET_LINK_LIBS_OK})
62             endif()
63             endmacro()
64              
65             macro(add_library)
66             set(args ${ARGV})
67             list(FIND args IMPORTED index)
68             if (index GREATER_EQUAL 0)
69             MATH(EXPR index "${index}+1")
70             list (INSERT args ${index} GLOBAL)
71             endif()
72             message(STATUS "add_library: ${args}")
73             _add_library(${args})
74             endmacro()
75              
76             add_subdirectory(".." "../build")
77              
78             function(get_all_libs_locations ret tgt)
79             set(self_loc "")
80             get_target_property(lret ${tgt} TYPE)
81             if (NOT ${lret} STREQUAL INTERFACE_LIBRARY)
82             get_target_property(lret ${tgt} IMPORTED_LOCATION)
83             message(STATUS "got:" ${lret} "for" ${tgt})
84             if (lret)
85             set(self_loc ${lret})
86             endif()
87             endif()
88             get_target_property(deps ${tgt} INTERFACE_LINK_LIBRARIES)
89             message(STATUS "deps:" ${deps} "for" ${tgt})
90             foreach(lib ${deps})
91             if (TARGET ${lib})
92             get_all_libs_locations(lret ${lib})
93             list(APPEND self_loc ${lret})
94             endif()
95             endforeach()
96             set(${ret} ${self_loc} PARENT_SCOPE)
97             endfunction()
98              
99             function(write_all_libs_inc tgt)
100             get_target_property(deps ${tgt} INTERFACE_LINK_LIBRARIES)
101             message(STATUS "deps inc:" ${deps} "for" ${tgt})
102             foreach(lib ${deps})
103             if (TARGET ${lib})
104             get_target_property(lret ${lib} INTERFACE_INCLUDE_DIRECTORIES)
105             message(STATUS "GOT_INC=" ${lret})
106             write_all_libs_inc(${lib})
107             endif()
108             endforeach()
109             endfunction()
110              
111             foreach(PROP ${REQUESTED_PROPS})
112             get_target_property(GOT_RES ${REQUESTED_TARGET} ${PROP})
113             if (GOT_RES)
114             message(STATUS "GOT_${PROP}=" "${GOT_RES}")
115             else (GOT_RES)
116             message(STATUS "GOT_${PROP}=")
117             endif (GOT_RES)
118             endforeach()
119              
120             get_target_property(libs ${REQUESTED_TARGET} INTERFACE_LINK_LIBRARIES)
121             if(libs)
122             foreach(lib ${libs})
123             if (NOT TARGET ${lib})
124             list(APPEND lib_result ${lib})
125             endif()
126             endforeach()
127             message(STATUS "GOT_FILTERED_LINK_LIBRARIES=" "${lib_result}")
128             endif()
129              
130             foreach(TARG ${CONF_TARGETS})
131             separate_arguments(OPT UNIX_COMMAND ${${TARG}_COMP_OPTIONS})
132             target_compile_options(${TARG} PRIVATE ${OPT})
133             endforeach()
134              
135             get_all_libs_locations(locs ${REQUESTED_TARGET})
136             message(STATUS "GOT_LOCATIONS=" "${locs}")
137              
138             write_all_libs_inc(${REQUESTED_TARGET})
139              
140             EOS
141              
142 0           close(CMAKELISTS);
143              
144 0           my @properties = qw(INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS INTERFACE_INCLUDE_DIRECTORIES INTERFACE_LINK_DIRECTORIES INTERFACE_LINK_LIBRARIES INTERFACE_LINK_OPTIONS OUTPUT_NAME NAME IMPORT_PREFIX IMPORT_SUFFIX LINK_LIBRARIES LINK_OPTIONS LINK_FLAGS IMPORTED_LOCATION);
145 0           my $prop_list = join ';', @properties;
146              
147              
148 0           return `cd $props_dir && cmake . -G "Unix Makefiles" $options -DREQUESTED_TARGET=$target -DREQUESTED_PROPS="$prop_list"`;
149             }
150              
151             sub import_cmake_properites {
152 0     0 0   my $source = shift;
153 0           my $result = {
154             INSTALL_INCLUDE => _get_prop($source, 'INTERFACE_INCLUDE_DIRECTORIES', 'INSTALL_INTERFACE'),
155             BUILD_INCLUDE => _get_prop($source, 'INTERFACE_INCLUDE_DIRECTORIES', 'BUILD_INTERFACE'),
156             INC => _get_prop($source, 'INC', 'INSTALL_INTERFACE'),
157             };
158              
159 0           my $libs = _get_prop($source, 'FILTERED_LINK_LIBRARIES');
160 0           my $link_opts = _get_prop($source, 'INTERFACE_LINK_OPTIONS');
161 0           my $locations = _get_prop($source, 'LOCATIONS');
162              
163 0 0         push ( @$link_opts, map({($_ =~ /-/) ? $_ : "-l$_"} @$libs), @$locations );
  0            
164 0           $result->{"LIBS"} = $link_opts;
165              
166 0           $result->{"DEFINE"} = [map {"-D$_"} @{_get_prop($source, 'INTERFACE_COMPILE_DEFINITIONS')}];
  0            
  0            
167 0           $result->{"CCFLAGS"} = _get_prop($source, 'IMPORT_COMPILE_OPTIONS');
168              
169 0           my $ok = eval { require Alien::cmake3; 1 };
  0            
  0            
170 0 0         die "This module requires Alien::cmake3 to build.\n" unless $ok;
171 0           $result->{"CMAKE_BIN"} = File::Spec->catfile(Alien::cmake3->bin_dir, Alien::cmake3->exe);
172              
173 0           return $result;
174             }
175              
176             sub _get_raw_prop {
177 0     0     my ($source, $prop_name) = @_;
178 0           my @result = ($source =~ /(?<=GOT_$prop_name=)(.+?)$/gm);
179 0           return \@result;
180             }
181              
182             sub _split_cmake_generator {
183 0     0     my $str = shift;
184 0           return ;
185             }
186              
187             sub _transform_cmake_generator {
188 0     0     my ($vals, $generator_key) = @_;
189 0           my @result;
190 0           for my $str (@$vals) {
191 0           my @splited = ($str =~ /(?:\$<.*?>)|(?:[^\$;]+)/g);
192 0           for my $val (@splited) {
193 0 0         if ($val =~ /\$<$generator_key:(.*)>/g) {
194 0           push @result, split(/;/, $1);
195 0           next;
196             }
197 0 0         if ($val =~ /\$/g) { #other generate expression
198 0           next;
199             }
200 0           push @result, $val; #pure value without generators
201             }
202             }
203 0           return \@result;
204             }
205              
206             sub _get_prop {
207 0     0     my ($source, $prop_name, $generator_key) = @_;
208 0           my $res = _get_raw_prop($source, $prop_name);
209 0 0         if ($generator_key) {
210 0           return _transform_cmake_generator($res,$generator_key);
211             } else {
212 0           return [map{split(";", $_)} @$res];
  0            
213             }
214             }
215              
216             1;
217